【问题标题】:Accessing files beyond MAX_PATH in C#/.NET在 C#/.NET 中访问超出 MAX_PATH 的文件
【发布时间】:2010-11-14 12:08:59
【问题描述】:

背景

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

问题

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

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

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

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

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

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

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

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

【问题讨论】:

    标签: c# winapi pinvoke fileshare max-path


    【解决方案1】:

    BCL 团队制作了一个由 3 部分组成的系列,详细说明了做出这些选择的原因以及解决方法。如果您还没有阅读,我建议您阅读,因为它是有关该主题的重要信息来源

    【讨论】:

    • 是的,我看过这个。老实说,他们推荐的解决方案是我试图避免的。当我们处理文件和目录元数据、权限和文件内容时,这会触发大量 API 调用,我真的希望有人能提供一个可行的解决方案,这意味着我不必在下个月花费pinvoke.net ;)
    • 我自己的和其他的答案 here 建议您可以使用一些包装库来处理长路径。
    【解决方案2】:

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

    【讨论】:

      【解决方案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
          }
      }
      

      【讨论】:

      • 当我的 P/Invoke 定义类达到大约 3000 行各种导入、结构和常量时,我​​仍然没有我需要的所有功能,我想我会先来这里看看是否我错过了一些明显的东西......似乎没有:(
      • 明白了。并且没有现成的第三方解决方案?我很惊讶!
      【解决方案4】:

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

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

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 2010-09-11
          • 2011-02-19
          • 1970-01-01
          • 2014-01-03
          • 2019-07-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-09
          相关资源
          最近更新 更多