检查长度是否超过MAX_PATH,还是捕获PathTooLongException更好?

4
我正在编写一个使用System.IO方法处理文件和目录的C#程序。其中一些方法包括Directory.GetDirectories,Directory.GetFiles和Path.GetDirectoryName,如果路径太长,则所有这些方法都可能抛出PathTooLongException异常。我的第一个问题是,Microsoft .NET Framework是否强制执行路径的最大长度,就像在C++中调用Windows API一样? 在C#中,超过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 异常几乎一定更可靠,因为它是内置在你调用的代码中的。请注意,如果你不想处理这个异常,你甚至不需要 try/catch;只需让它向上传播到调用方即可。 - Robert Harvey
Windows 10 v1607及更高版本提供了选项以移除MAX_PATH限制,因此您不应人为地限制路径字符串。只需让操作系统在需要时失败,并在必要时捕获错误即可。 - Remy Lebeau
3个回答

6

"更好"是一种主观判断。

捕获异常比测试条件并避免出现异常的操作要慢得多。但是,除非您将遇到大量异常,否则性能差异根本不重要。

很难想象您会遇到大量路径过长错误的情况,除非您试图将树复制或移动到已经很深的目录节点中。在这种情况下,您最好事先对所有内容进行测试,以便不会创建一个可能在中途失败的大型缓慢操作。

然而,硬编码260也是一个坏主意,因为如前面的答案所示。

没有内置的Windows函数可以为给定系统提供实际答案,但您可以在用户系统上通过试错(可能是二分查找)来确定答案,然后再开始操作。

但是,如果您阅读我引用的文章,就会发现您可以在程序中轻松地创建比Windows中有效的路径更长的路径。 Windows资源管理器在达到255个字符后会出现问题,因此长话短说,如果您有任何选择的余地,我建议最多限制为255个字符。


3
硬编码数值到代码中通常不是最好的选择。顺便提一下,目录名必须小于 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;
     }

}

注意:此代码尚未经过测试。

0

我认为你不确定MAX_PATH的使用方式,这表明最好捕获异常而不是尝试自己进行检查。

我的一般哲学是实际使用数据的代码应该负责检查它是否有效。由于你的getFolderName方法除了将其传递给GetDirectoryName之外没有对path做任何事情,因此我不会费心检查长度,甚至可能不会检查它是否为空/ null。只需将其传递并让GetDirectoryName来处理。

当然,也有例外。例如,如果我有一个方法,它接收一堆参数,然后将这些参数传递给各种其他方法,我可能希望在前面执行一些检查,以便我不会因为只有一半参数有效而进入某种奇怪的状态。

顺便说一句,我相信C#(也许是.NET的全部)会自动将所有变量初始化为它们的默认值,因此将folderName初始化为String.Empty是多余的。


1
我相信C#(也许是.NET的全部)会自动将所有变量初始化为它们的默认值,因此将folderName初始化为String.Empty是多余的。String.Empty不是string的默认值:null才是。请考虑编辑您的答案以删除误导性信息。 - julealgon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接