C#访问无盘符映射NAS路径时出现路径非法字符报错问题
问题核心原因
- .NET原生文件系统API的路径校验逻辑不统一:
File.Exists、Directory.GetFiles/GetDirectories这几个方法内部做了WebDAV UNC路径的特殊兼容,能识别带@SSL@端口格式的WebDAV路径,正常返回存在结果、枚举文件列表;但File.Copy、Path.GetFileName这些方法走的是标准通用路径校验规则,会把路径段里的@特殊标记判定为非法字符直接抛错,这就是API行为不一致的根本原因。 - HTTPS协议路径本身就不在原生文件API的支持范围内,这类路径属于Web资源寻址范畴,只能通过HTTP请求类方法访问,你之前写的带认证的WebClient单文件下载逻辑是完全正确的。
- 你之前代码里的报错,本质是把WebDAV枚举返回的带特殊格式的UNC路径,直接传给了不兼容该格式的路径处理、文件复制方法,和下载间隔、协程逻辑没有关系。
正确批量复制实现方案
不要混用UNC路径做路径处理和文件读取:目录遍历可以用WebDAV的UNC路径拿全量文件、目录结构,但拿到路径后不要直接传给文件操作API,而是把UNC路径转换成对应的HTTPS下载地址,用已经验证可用的WebClient认证逻辑下载即可,完全绕开原生文件API的路径校验问题。
- 路径转换规则:把UNC前缀
\\Some.domain@SSL@50005\DavWWWRoot直接替换成HTTPS前缀https://Some.domain:50005,同时把路径里所有的反斜杠\替换成正斜杠/,就是对应文件的HTTP下载地址。 - 递归处理逻辑:
- 先用
Directory.GetDirectories、Directory.GetFiles枚举UNC根路径下的所有子目录、文件 - 枚举到子目录时,直接在本地对应路径创建同名文件夹,再递归处理子目录内的文件
- 枚举到文件时,按规则转成HTTPS地址,过滤掉带
~$的临时文件,用配置好认证信息的WebClient下载到本地对应路径即可
- 先用
可直接参考的实现代码:
// 初始化WebClient,复用已验证可用的配置 WebClient client = new WebClient(); client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)"); client.Credentials = new NetworkCredential("Name", "Password"); // 配置路径常量 string uncRoot = @"\\Some.domain@SSL@50005\DavWWWRoot\Folder"; string httpRoot = "https://Some.domain:50005/Folder"; string localRoot = @"D:\LocalBackup\Folder"; // 递归复制方法 void CopyWebDavFolder(string currentUncPath, string currentLocalPath) { // 创建本地对应目录 Directory.CreateDirectory(currentLocalPath); // 处理当前目录下所有文件 foreach (string uncFilePath in Directory.GetFiles(currentUncPath)) { string fileName = Path.GetFileName(uncFilePath); // 跳过Office临时文件 if (fileName.StartsWith("~$")) continue; // 拼接本地保存路径 string localSavePath = Path.Combine(currentLocalPath, fileName); // UNC路径转HTTP下载路径 string httpDownloadPath = uncFilePath.Replace(uncRoot, httpRoot).Replace('\\', '/'); // 下载文件,同步场景直接用DownloadFile即可 Console.WriteLine($"正在下载:{httpDownloadPath}"); client.DownloadFile(httpDownloadPath, localSavePath); } // 递归处理所有子目录 foreach (string uncDirPath in Directory.GetDirectories(currentUncPath)) { string dirName = Path.GetFileName(uncDirPath); string nextLocalPath = Path.Combine(currentLocalPath, dirName); CopyWebDavFolder(uncDirPath, nextLocalPath); } } // 启动复制 CopyWebDavFolder(uncRoot, localRoot);
注意:如果在Unity项目里要用协程做异步下载,不要直接用同步的
DownloadFile,可以把下载逻辑替换成之前用的DownloadData+File.WriteAllBytes的协程版本,路径转换、递归遍历的逻辑完全通用不需要修改。
内容的提问来源于stack exchange,提问作者Cunibon
相关产品推荐
相关产品推荐

