.net 如何读取共享文件 (UNC)

来源:互联网 发布:阳春政府网络问政 编辑:程序博客网 时间:2024/05/16 08:36

在 Windows 下, 我们经常会访问到这样的地址

\\ComputerName\SharedFolder\Resource

这种资源样式, 正式的名字叫 UNC ( Uniform Naming Convention ) 

是 Windows 环境下, 描述文件资源在网络上的位置一种语法 

它可以描述 folder, file, printer 等网络资源 (是的 Windows 下的打印机也是用 UNC 访问的)


那我们如何通过 .net 来访问这样地址下的资源呢? 有没有现成的 .net api 呢? 

回答是遗憾的, 目前 .net 托管代码还没有支持这样的 api 


但山不转水转, windows32 api 是可以支持的, 也就是说我们可以利用 .net Plantform Invoke 援引 windows32 api 来访问 UNC 资源. 


Stackoverflow 上提供了详细解决方案

http://stackoverflow.com/questions/659013/accessing-a-shared-file-unc-from-a-remote-non-trusted-domain-with-credentials/684040#684040


我们需要创建一个能连接 UNC 资源的类

public class NetworkShareAccesser : IDisposable{#region Const private const int RESOURCETYPE_DISK = 0x00000001;private const int CONNECT_INTERACTIVE = 0x00000008;private const int CONNECT_PROMPT = 0x00000010;private const int CONNECT_UPDATE_PROFILE = 0x00000001;private const int NO_ERROR = 0;#endregionprivate string _remoteUncName;private string _remoteComputerName;public string RemoteComputerName{get{return _remoteComputerName;}set{_remoteComputerName = value;_remoteUncName = @"\\" + this._remoteComputerName;}}public string UserName { get; set; }public string Password { get; set; }#region PInvoke Signatures[DllImport("Mpr.dll")]private static extern int WNetUseConnection(IntPtr hwndOwner,NETRESOURCE lpNetResource,string lpPassword,string lpUserID,int dwFlags,string lpAccessName,string lpBufferSize,string lpResult);[DllImport("Mpr.dll")]private static extern int WNetCancelConnection2(string lpName,int dwFlags,bool fForce);[StructLayout(LayoutKind.Sequential)]private class NETRESOURCE{public int dwScope = 0;public int dwType = 0;public int dwDisplayType = 0;public int dwUsage = 0;public string lpLocalName = "";public string lpRemoteName = "";public string lpComment = "";public string lpProvider = "";}#endregion/// <summary>/// Creates a NetworkShareAccesser for the given computer name. The user will be promted to enter credentials/// </summary>/// <param name="remoteComputerName"></param>/// <returns></returns>public static NetworkShareAccesser Access(string remoteComputerName){return new NetworkShareAccesser(remoteComputerName);}/// <summary>/// Creates a NetworkShareAccesser for the given computer name using the given domain/computer name, username and password/// </summary>/// <param name="remoteComputerName"></param>/// <param name="domainOrComuterName"></param>/// <param name="userName"></param>/// <param name="password"></param>public static NetworkShareAccesser Access(string remoteComputerName, string domainOrComuterName, string userName, string password){return new NetworkShareAccesser(remoteComputerName,domainOrComuterName + @"\" + userName,password);}/// <summary>/// Creates a NetworkShareAccesser for the given computer name using the given username (format: domainOrComputername\Username) and password/// </summary>/// <param name="remoteComputerName"></param>/// <param name="userName"></param>/// <param name="password"></param>public static NetworkShareAccesser Access(string remoteComputerName, string userName, string password){return new NetworkShareAccesser(remoteComputerName,userName,password);}private NetworkShareAccesser(string remoteComputerName){RemoteComputerName = remoteComputerName;this.ConnectToShare(this._remoteUncName, null, null, true);}private NetworkShareAccesser(string remoteComputerName, string userName, string password){RemoteComputerName = remoteComputerName;UserName = userName;Password = password;this.ConnectToShare(this._remoteUncName, this.UserName, this.Password, false);}private void ConnectToShare(string remoteUnc, string username, string password, bool promptUser){NETRESOURCE nr = new NETRESOURCE{dwType = RESOURCETYPE_DISK,lpRemoteName = remoteUnc};int result;if (promptUser){result = WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null);}else{result = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null);}if (result != NO_ERROR){throw new Win32Exception(result);}}private void DisconnectFromShare(string remoteUnc){int result = WNetCancelConnection2(remoteUnc, CONNECT_UPDATE_PROFILE, false);if (result != NO_ERROR){throw new Win32Exception(result);}}/// <summary>/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources./// </summary>/// <filterpriority>2</filterpriority>public void Dispose(){this.DisconnectFromShare(this._remoteUncName);}}


怎么使用这个类 ? 


[TestMethod]public void Access(){using (NetworkShareAccesser.Access("server ip", "username", "password")){var file = new FileInfo(@"\\serverip\xxx.txt");Assert.IsNotNull(file);}}


另外需要注意,  一个 Windows 用户访问一个 UNC 资源, 只允许有一个 UNC 连接, 

当使用 Windows Explorer 来访问 UNC 的资源, 等于创建了一个 UNC 连接, 

而且这个连接会一直被存着, 当我们还没有释放此连接前, 用 NetworkShareAccesser 访问同样资源时会报 1219 的错误 (多连接冲突)

这个时候, 我们只要把 Windows Explorer 关闭连接被释放, 再使用 NetworkShareAccesser 来访问就不会报 1219 错误了. 







0 0
原创粉丝点击