在C#/ .NET中访问MAX_PATH之外的文件

时间:2009-07-27 21:08:48

标签: c# winapi pinvoke fileshare max-path

背景

我需要使用最高版本的.NET 2.0编写一个工具(使用现成的东西,因为出于政治,商业和保密/信任的原因,这个客户端不能选择将文件从一个服务器迁移到另一个服务器)网络。服务器是本地团队的文件服务器,某些团队文件夹需要迁移到其他服务器以便于重组。基本的想法是我们读取每个文件并在数小时内通过网络流式传输,几天后数据将被迁移。需要保留文件权限。由于这将花费几天时间(我们正在谈论几千兆字节的数据,对于一些团队而言),我们需要每晚迭代文件并比较修改日期并更新已更改的日期。理论上说,最终新服务器将拥有最新的文件副本,用户可以切换到新服务器。它当然不是那么简单,但我们有一个我们认为应该有效的设计:)

问题

所以理论上我们只是打开文件,通过网络传输,然后在另一端写,对吗? :)

不幸的是,在服务器本身上,文件共享是在文件夹路径中创建的,例如:

  

D:\ Data \ Team Shares \ DIVISION \ DEPARTMENT \ NAME OF TEAM - 可能会长篇大论\

对于每个用户,此路径将映射到驱动器,例如,它将作为\\ SERVER \ TEAMNAME共享并映射到T:驱动器。

这导致了从T:驱动器可见的文件在MAX_PATH限制内的情况,但是当在服务器本身上本地查看时,它们会超出它。我们无法使用网络共享来访问文件,因为这个工具需要是通用的,要在数百个这样的服务器上运行,并且没有标准的方法来判断哪些文件共享是我们应该移动的文件共享和那些不是 - 甚至没有命名约定标准。此外,偶尔会有其他股份的子股,所以我们超过MAX_PATH两倍的限额!

我知道使用“\\?\”前缀指定路径的解决方法,该路径将路径视为UNC路径,并允许理论上最多32k个字符。

这种解决方法是在Win32 API级别实现的,System.IO命名空间(大部分)基本上只是本机Win32 API函数的一个薄包装器,但是微软在关闭呼叫之前“有帮助”地实现了额外的(不正确的)验证到API。在这种情况下,.NET Framework拒绝该路径,因为它声称'?'是一个无效的路径字符。

所以我的问题是......有没有一种方法我没有想到这将允许我解决这个问题,而不必完全重写几乎整个System.IO命名空间,加载P / Invoke调用,只是为了消除这种恼人的验证?

5 个答案:

答案 0 :(得分:5)

BCL团队完成了3部分关于这些选择的确切原因以及解决方法的内容。如果您还没有阅读,我建议您这样做,因为它是有关该主题的重要信息来源

答案 1 :(得分:4)

我遇到了一个可能有用的第三方解决方案:AlphaFS

答案 2 :(得分:1)

假设您的软件具有必要的权限,通过一些平台调用来解决此限制应该相当容易:

[DllImport("kernel32.dll", SetLastError = true)]
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
  uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
  uint dwFlagsAndAttributes, IntPtr hTemplateFile);

// Must close/dispose handle separately from FileStream since it's not owned by
// that object when passed to constructor.
using (SafeFileHandle h = CreateFile(longUncPath, GENERIC_WRITE, 0, IntPtr.Zero, 
       OPEN_EXISTING, 0, IntPtr.Zero))
{
    using (var fs = new FileStream(h, FileAccess.Read))
    {
        // operations with FileStream object
    }
}

答案 3 :(得分:0)

您可以尝试通过使用subst.exe(或其内部使用的任何API)映射父目录来缩短路径:

http://www.makeuseof.com/tag/how-to-map-a-local-windows-folder-to-a-drive-letter/

理想情况下,你会尽可能多地绘制路径。

答案 4 :(得分:-1)

我使用以下小脚本删除了目录结构。 pushd使用UNC格式,它给你32K而不是260限制

set "folder=\\SERVER\SHARE\DIVISION\DEPARTMENT\NAME OF TEAM - COULD BE FAIRLY LONG\" 
pushd "%folder%"
for /d %%i in ("*") do rmdir "%%i" /s /q
popd