3

我在 .Net 4.0 中使用 DirectoryInfo 和 FileInfo 来枚举目录树中的文件,我遇到了 PathTooLongException。简化版如下

public static class Test
{
    public static void Search(DirectoryInfo base)
    {
        foreach(var file in base.GetFiles())
        {
            try
            {
                Console.WriteLine(file.FullName);
            } catch(PathTooLongException ex)
            {
                // What path was this?
            }
        }
        foreach(var dir in base.GetDirectories())
        {
            Search(dir);
        }
    }
}

抛出错误时,我想知道是什么文件路径导致了问题。显然我不能要求,FullName因为那是错误的。我可以从中获取名称file.Name,但是如果我无法获取路径的其余部分,即使从 中找到该文件也可以正常工作file.Directory!(我不能使用它,因为实际代码要复杂得多)。PathTooLongExceptionDirectoryInfo

查看堆栈跟踪,它似乎正在使用内部路径(我看到一个受保护file.FullPath的调试),并试图从完整(超大)路径中删除目录。大多数问题似乎都涉及System.IO.Path.NormalizePath,我听说在 .Net 4.0 中经历了一些变化。我没有尝试过以前版本的框架。

我的问题:

  1. 我怎样才能从这个异常中得到完整的路径;它似乎在没有任何有用信息的情况下通过了。
  2. 为什么框架需要限制路径中的字符来截断文件名?

在此先感谢您的帮助,
安迪

4

1 回答 1

6

除了使用反射,或者使用库或 P/Invoke 来使用支持长路径和手动检查长度的 Windows API 之外,我想不出任何其他方法。完整路径存储在一个protected string名为FullPath

foreach(var dir in new DirectoryInfo (@"D:\longpaths")
                     .GetFileSystemInfos("*.*", SearchOption.AllDirectories))
{
    try
    {
        Console.WriteLine(dir.FullName);
    }
    catch (PathTooLongException)
    {
                FieldInfo fld = typeof(FileSystemInfo).GetField(
                                        "FullPath", 
                                         BindingFlags.Instance | 
                                         BindingFlags.NonPublic);
                Console.WriteLine(fld.GetValue(dir));  // outputs your long path
    }
}

如果您尝试对文件进行实际操作,而不仅仅是检查文件长度,我建议您使用Microsoft 的 BCL 团队提供的此类库,但它不会创建DirectoryInfosFileInfo或者FileSystemInfo仅创建字符串。因此,它看起来可能不是您代码的直接替代品。

至于第二个问题的答案,我建议阅读这篇关于 .NET 中长路径的博文。这是它的引述,解释了为什么他们没有快速在 .NET 中添加长路径支持。

很少有人抱怨 32K 的限制,那么,问题解决了吗?不完全的。过去我们不愿意添加长路径有几个原因,以及为什么我们仍然对此保持谨慎,这与安全性、Windows API 对 \?\ 语法的不一致支持以及应用程序兼容性有关。

这是一个由 3 部分组成的系列,解释了 API 为何如此的几个原因以及存在限制的原因。

于 2012-03-06T18:03:33.457 回答