最好检查长度是否超过MAX_PATH或捕获PathTooLongException

本文关键字:PATH PathTooLongException MAX 检查 是否 | 更新日期: 2023-09-27 18:02:47

我正在编写一个使用System.IO方法处理文件和目录的c#程序。其中一些方法包括Directory.GetDirectoriesDirectory.GetFilesPath.GetDirectoryName,如果路径太长,它们都可能抛出PathTooLongException异常。我的第一个问题是,微软。net框架是否强制执行路径的最大长度,就像在c++中调用Windows API一样?c#中的路径(在string中)超过MAX_PATH会导致PathTooLongException被抛出吗?

我应该使用这个吗?

string getFolderName(string path) 
{
    if (string.IsNullOrWhiteSpace(path))
        return string.Empty;
    if (path.Length > 260)
    {
        System.Diagnostics.Debug.WriteLine("Path is too long.");
        return string.Empty;
    }
    string folderName = System.IO.Path.GetDirectoryName(path);
    return folderName;
}

还是这个?

string getFolderName(string path) 
{
    if (string.IsNullOrWhiteSpace(path))
        return string.Empty;
    string folderName = string.Empty;
    try {
        folderName = System.IO.Path.GetDirectoryName(path);
    }
    catch (System.IO.PathTooLongException)
    {
        System.Diagnostics.Debug.WriteLine("Path is too long.");
    }
    return folderName;
}

最好检查长度是否超过MAX_PATH或捕获PathTooLongException

孰优孰劣

捕获异常比测试条件和完全避免异常要慢得多。但是,除非您将要遇到大量异常,否则性能差异并不重要。

很难想象你会得到大量的路径过长错误,除非你试图做一些事情,复制或移动树到一个已经很深的目录节点。在这种情况下,您最好预先测试所有内容,这样您就不会创建一个会在中间失败的大型缓慢操作。

然而,正如前面的答案所示,硬编码的260无论如何都是一个坏主意。

没有内置的windows函数可以给出给定系统的真实答案,但是在开始操作之前,您可以简单地在用户系统上通过试错(可能是二进制搜索)来确定答案。

然而,如果您阅读了我所引用的文章,您将会看到,您可以轻松地在程序中创建比在windows中更长的路径。Windows资源管理器一旦达到255个字符就会出现问题,所以长话短说,如果您有选择的话,我建议最多限制为255个字符。

将值硬编码到代码中通常不是最好的主意。仅供参考,目录名必须小于 248字符,最大文件名长度小于 260字符。如果你正在寻找太长的路径,你现有的代码已经有一个漏洞。

这个问题解决了这个问题并提供了一些解决方案。如果您希望使用固定长度的路径,您可以这样做

public static bool IsPathWithinLimits (string fullPathAndFilename)
{
     const int MAX_PATH_LENGTH = 259;//260-1
     return fullPathAndFilename.Length<=MAX_PATH_LENGTH;
}

您也可以使用反射来查找最大路径长度。我会使用反射来获得一次最大路径长度,然后存储该变量并在随后的调用中使用它。

public class PathHelper
{
     private static int MaxPathLength {get; set;}
     static PathHelper()
     {
          // reflection
          FieldInfo maxPathField = typeof(Path).GetField("MaxPath", 
              BindingFlags.Static | 
              BindingFlags.GetField | 
              BindingFlags.NonPublic );
          // invoke the field gettor, which returns 260
          MaxPathLength = (int) maxPathField.GetValue(null);
         //the NUL terminator is part of MAX_PATH https://msdn.microsoft.com/en-us/library/aa365247.aspx#maxpath
               MaxPathLength--; //So decrease by 1
     }

     public static bool IsPathWithinLimits (string fullPathAndFilename)
     {          
          return fullPathAndFilename.Length<=MaxPathLength;
     }
}

我认为您不确定MAX_PATH在底层是如何使用的这一事实表明,最好是捕获异常,而不是试图自己执行检查。

我的一般哲学是,实际使用数据块的代码应该负责检查它的有效性。因为你的getFolderName方法不与path做任何事情,而不是将其传递给GetDirectoryName,我不会费心检查长度,甚至可能不会费心检查它是否为空/null。把它传下去,让GetDirectoryName去操心吧。

当然,这条规则也有例外。例如,如果我有一个方法,它接受了一堆参数,然后将这些参数传递给各种其他方法,我可能想要提前执行一些检查,这样我就不会因为只有一半的参数是有效的而陷入某种奇怪的状态。

作为旁注,我相信c#(可能是所有。net)会自动将所有变量初始化为默认值,因此将folderName初始化为String.Empty是多余的。