在C#/.NET中访问超出最大路径的文件

在C#/.NET中访问超出最大路径的文件,c#,winapi,pinvoke,fileshare,max-path,C#,Winapi,Pinvoke,Fileshare,Max Path,背景 我需要编写一个最高使用.NET 2.0版的工具(出于政治、商业和机密性/信任原因,此客户端不能选择使用现成的工具)通过网络将文件从一台服务器迁移到另一台服务器。服务器是本地团队的文件服务器,某些团队文件夹需要迁移到其他服务器以便于重组。其基本思想是我们读取每个文件并在数小时内通过网络传输,几天后数据将被迁移。需要保留文件权限。由于这需要几天的时间(对于一些团队,我们讨论的数据高达几GB),因此我们需要每晚迭代文件,比较修改日期并更新已更改的日期。理论是,最终新服务器将拥有文件的最新副本,用

背景

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

问题

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

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

D:\Data\Team Shares\DIVISION\DEPARTMENT\Team的名称-可能相当长\

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

这导致了这样一种情况,即从T:驱动器可见的文件在
MAX\u路径
限制内,但是当在服务器本身上本地查看时,它们远远超出了限制。我们无法使用网络共享访问文件,因为该工具需要是通用的,在数百台服务器上运行,并且没有标准的方法来区分哪些文件共享是我们应该移动的,哪些不是-甚至没有命名约定标准。此外,偶尔也会有其他股票的子股票,因此我们两次超过了
MAX\u路径
限制

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

此解决方案是在Win32 API级别实现的,System.IO名称空间(大部分)基本上只是本地Win32 API函数的一个薄包装,但是Microsoft在将调用交给API之前“有用地”实现了额外的(不正确的)验证。在本例中,.NET Framework拒绝该路径,因为它声称“?”是无效的路径字符


所以我的问题是。。。有没有一种我没有想到的方法可以让我解决这个问题,而不必完全重写几乎整个System.IO名称空间,进行大量的P/Invoke调用,只是为了删除这个恼人的验证?

BCL团队编写了一个由3部分组成的系列文章,详细介绍了做出这些选择的原因和解决方法。如果你还没有读过,我建议你读,因为这是关于这个主题的一个很好的信息来源


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

[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
    }
}

我遇到了一个可能有帮助的第三方解决方案:。

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


理想情况下,您应该尽可能多地映射路径。

我使用下面的小脚本成功地删除了目录结构。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

是的,我看过这个。老实说,他们推荐的解决方案正是我试图避免的。当我们处理文件和目录元数据、权限和文件内容时,会遇到很多API调用,我真的希望有人能找到一个可行的解决方案,这意味着我不必花下一个月的时间在pinvoke.net;)我自己的答案和其他答案建议使用一些包装器库来处理长路径。当我的P/Invoke定义类有大约3000行不同的导入、结构和常量时,我仍然没有我需要的所有功能,我想我应该先来看看我是否遗漏了一些明显的东西。。。似乎没有:(明白了。而且没有现有的第三方解决方案?我很惊讶!