問題來源
文件服務器文件夾操作在PC與Surface端確實還是和傳統操作一樣沒什么區別,但是到了手機端與Surface Hub就沒那么方便了,因為文件資源管理器Explorer根本沒法添加網路硬盤。對於傳統行業以及擔心雲端文件安全的企業固然還是希望能使用文件服務器,特別是SurfaceHub用戶。SurfaceHub用戶開會的時候會用到很多敏感文件,這個時候如果無法訪問內部機密文件服務器,那還有什么用處?
解決方法
由於SurfaceHub只能安裝UWP應用,自然首先考慮UWP的實現。目前支持SurfaceHub的應用只有Yuki Explorer與Metro commander,Total Commander暫時不支持。兩者也許是使用了以下提到的開源項目SharpCifs??
方法一:文件類型關聯(只支持單個用戶與Guest用戶)
文件服務器文件路徑其實就是UNC路徑,在StorageFolder說明里面有如下文字:
實現:
1,添加權限
2,添加文件類型關聯
3,文件服務器文件操作(必須事先將文件服務器的認證信息保存在Window憑據里)
public class ShareFolderService { /// <summary> /// get items from unc path /// *you must add the /// </summary> /// <param name="uncPath"></param> /// <returns></returns> public async Task<IReadOnlyList<IStorageItem>> GetShareFolderItemsAsync(string uncPath) { var folder = await getFolderFromUncPath(uncPath); return await folder.GetItemsAsync(); } /// <summary> /// create item to share folder /// </summary> /// <param name="uncPath"></param> /// <param name="name"></param> /// <param name="isFile"></param> /// <returns></returns> public async Task<IStorageItem> ShareFolderCreateItemAsync(string uncPath, string name, bool isFile = true) { var shareFolder = await getFolderFromUncPath(uncPath); if (isFile) { return await shareFolder.CreateFileAsync(name, CreationCollisionOption.ReplaceExisting); } else { return await shareFolder.CreateFolderAsync(name, CreationCollisionOption.OpenIfExists); } } private async Task<StorageFolder> getFolderFromUncPath(string uncPath) { return await StorageFolder.GetFolderFromPathAsync(uncPath); } }
缺點:
- 用戶固定無法自由切換
- 無法查看全部文件
- 在SurfaceHub端將導致雙擊文件無法啟動(SurfaceHub Bug)
方法二:SMB協議實現(支持全部用戶)
概述:
服務器信息塊(SMB)協議是一種IBM協議,用於在計算機間共享文件、打印機、串口等。SMB 協議可以用在因特網的TCP/IP協議之上,也可以用在其它網絡協議如IPX和NetBEUI 之上。
SMB 一種客戶機/服務器、請求/響應協議。通過 SMB 協議,客戶端應用程序可以在各種網絡環境下讀、寫服務器上的文件,以及對服務器程序提出服務請求。此外通過 SMB 協議,應用程序可以訪問遠程服務器端的文件、以及打印機、郵件槽(mailslot)、命名管道(named pipe)等資源。
在 TCP/IP 環境下,客戶機通過 NetBIOS over TCP/IP(或 NetBEUI/TCP 或 SPX/IPX)連接服務器。一旦連接成功,客戶機可發送 SMB 命令到服務器上,從而客戶機能夠訪問共享目錄、打開文件、讀寫文件,以及一切在文件系統上能做的所有事情。
從 Windows 95 開始,Microsoft Windows 操作系統(operating system)都包括了客戶機和服務器 SMB 協議支持。Microsoft 為 Internet 提供了 SMB 的開源版本,即通用 Internet 文件系統 (CIFS)。與現有 Internet 應用程序如文件傳輸協議(FTP)相比, CIFS 靈活性更大。對於 UNIX 系統,可使用一種稱為 Samba 的共享軟件。
Windows的Explorer實現原理如下:
Windows系統本身就是一個SMB服務器,支持版本如下:
除了Windows系統以外,UNIX與Mac或者Android系統都可以安裝SMB軟件訪問各類文件服務器系統的文件。
JAVA開源項目:JCIFS
JCIFS 是一個純 JAVA 編寫的實現 CIFS/SMB 協議的開源項目。它由 samba 組織負責維護開發。 JCIFS 是一個完整的,豐富的,具有可擴展能力且線程安全的客戶端庫。這一庫可以應用於各種 JAVA 虛擬機訪問遵循 CIFS/SMB 網絡傳輸協議的網絡資源,包括 Windows 下的共享資源和 Linux & Unix 下的 SAMBA 資源。
.NET開源項目:
- SharpCifs :從JCIFS轉換而來,支持Windows Phone 8.1 (Silverlight) 。
- SharpCifs.Std :從SharpCifs轉換而來,支持Xamarin & .NET Core 。Nuget包:Install-Package SharpCifs.Std –Pre
實現:
主要使用SharepCifs.Std來實現。由於SharepCifs.Std類庫使用了UWP不支持的包:
- System.Console (>= 4.3.0)
System.Threading.Thread (>= 4.3.0)
所有需要將以上兩個包做替換處理:
- System.Console (>= 4.3.0)關聯的Console.Error與Console.Write方法替換為StringWriter的Write方法
- System.Threading.Thread (>= 4.3.0) 替換成Task方法(CurrentThread方法可以為空)
- Dns.GetHostName()需要替換回SharepCifs的方法
讀取文件夾列表:
var folder = new SmbFile("smb://UserName:Password@ServerName/ShareName/Folder/")); var epocDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); foreach (var item in folder.ListFiles()) { var lastModDate = epocDate.AddMilliseconds(item.LastModified()).ToLocalTime(); Log.WriteLine($"Name: {item.GetName()}, isDir?: {item.IsDirectory()}, Date: {lastModDate.ToString("yyyy-MM-dd HH:mm:ss")}"); }
讀取文件:
var file = new SmbFile("smb://UserName:Password@ServerName/ShareName/Folder/FileName.txt")); var readStream = file.GetInputStream(); var buffer = new byte[1024*8]; var memStream = new MemoryStream(); int size; while ((size = readStream.Read(buffer, 0, buffer.Length)) > 0) memStream.Write(buffer, 0, size); Log.WriteLine(Encoding.UTF8.GetString(memStream.ToArray()));
創建文件:
var file = new SmbFile("smb://UserName:Password@ServerName/ShareName/Folder/NewFileName.txt")); file.CreateNewFile(); var writeStream = file.GetOutputStream(); writeStream.Write(Encoding.UTF8.GetBytes("Hello!"));
優點:
- 由於需要用戶名與密碼所有支持所有用戶(含Guest)
- 支持所有設備(SurfaceHub,Android,iOS等)
- 支持所有文件類型
備注:
目前打算將次代碼轉換為PCL類庫,以供在Xamarin項目中實現。