当路径太长时,File.Exists()错误地返回false

时间:2012-06-26 15:11:00

标签: c# .net

我目前正在开发一个遍历各种目录的程序,以确保使用File.Exists()存在特定文件。

应用程序声称某些文件实际存在时不存在,我最近发现此错误是由于路径太长。

我发现SO上有一些问题可以解决File.Exists()返回错误值的问题,但似乎都没有解决这个问题。

重命名目录和文件以缩短路径实际上不是一个选项,所以我不知道此时该怎么做。有解决这个问题的解决办法吗?

正在使用的代码没有什么特别之处(我已经删除了一些不相关的代码),但我会将其包含在下面以防它有用。

    private void checkFile(string path)
    {
        if (!File.Exists(path))
            Console.WriteLine("   *  File: " + path + " does not exist.");
    }

5 个答案:

答案 0 :(得分:12)

来自MSDN - Naming Files, Paths, and Namespaces

  

在Windows API中(以下讨论了一些例外情况)   段落),路径的最大长度是MAX_PATH,即   定义为260个字符。

     

...

     

Windows API具有许多也具有Unicode版本的函数   允许一个扩展长度的路径,最大总路径长度为   32,767个字符。这种类型的路径由组件组成   用反斜杠分隔,每个都取决于返回的值   GetVolumeInformation的lpMaximumComponentLength参数   function(此值通常为255个字符)。 指定   扩展长度路径,使用"\\?\"前缀。例如,"\\?\D:\very long path"

     

...

     

因为您不能将"\\?\"前缀与相对路径一起使用,   相对路径始终限制为总共MAX_PATH个字符。

(强调补充)

如果所有路径都是完整路径,则可以更新代码以使用扩展长度路径说明符,如下所示:

const longPathSpecifier = @"\\?";

private void checkFile(string path)
{
    // Add the long-path specifier if it's missing
    string longPath = (path.StartsWith(longPathSpecifier) ? path : longPathSpecifier  + path);

    if (!File.Exists(longPath))
    {
        // Print the original path
         Console.WriteLine("   *  File: " + path + " does not exist.");
    }
}

<强>更新

  

对于文件I / O,&#34; \?\&#34;路径字符串的前缀告诉Windows   用于禁用所有字符串解析并发送后续字符串的API   它直接到文件系统。例如,如果是文件系统   支持大路径和文件名,可以超过MAX_PATH   Windows API强制执行的限制。

至少在我的系统上(使用Windows 7),不支持长文件名,因此我无法验证上述解决方案是否适合您。

更新:我找到了一个可行的解决方案,但它相当难看。这是我在伪代码中所做的:

  1. 将路径拆分为目录数组
  2. 获取路径中长度小于260个字符的部分(MAX_PATH)。
  3. 为路径的该部分创建DirectoryInfo(&#34; dir&#34;以备将来参考)。
  4. 对于路径中的其余目录:
    一个。调用dir.GetDirectories()并检查结果中是否包含下一个目录 湾如果是这样,请将dir设置为DirectoryInfo并继续挖掘 C。如果没有,则路径不存在
  5. 一旦我们浏览了导致我们文件的所有目录,请调用dir.GetFiles()并查看我们的文件是否存在于返回的FileInfo对象中。

答案 1 :(得分:10)

这是丑陋而低效的,但它可以绕过MAX_PATH限制:

const int MAX_PATH = 260;

private static void checkPath(string path)
{
    if (path.Length >= MAX_PATH)
    {
        checkFile_LongPath(path);
    }
    else if (!File.Exists(path))
    {
        Console.WriteLine("   *  File: " + path + " does not exist.");
    }
}

这是checkFile_LongPath函数:

private static void checkFile_LongPath(string path)
{
    string[] subpaths = path.Split('\\');
    StringBuilder sbNewPath = new StringBuilder(subpaths[0]);
    // Build longest subpath that is less than MAX_PATH characters
    for (int i = 1; i < subpaths.Length; i++)
    {
        if (sbNewPath.Length + subpaths[i].Length >= MAX_PATH)
        {
            subpaths = subpaths.Skip(i).ToArray();
            break;
        }
        sbNewPath.Append("\\" + subpaths[i]);
    }
    DirectoryInfo dir = new DirectoryInfo(sbNewPath.ToString());
    bool foundMatch = dir.Exists;
    if (foundMatch)
    {
        // Make sure that all of the subdirectories in our path exist.
        // Skip the last entry in subpaths, since it is our filename.
        // If we try to specify the path in dir.GetDirectories(), 
        // We get a max path length error.
        int i = 0;
        while(i < subpaths.Length - 1 && foundMatch)
        {
            foundMatch = false;
            foreach (DirectoryInfo subDir in dir.GetDirectories())
            {
                if (subDir.Name == subpaths[i])
                {
                    // Move on to the next subDirectory
                    dir = subDir;
                    foundMatch = true;
                    break;
                }
            }
            i++;
        }
        if (foundMatch)
        {
            foundMatch = false;
            // Now that we've gone through all of the subpaths, see if our file exists.
            // Once again, If we try to specify the path in dir.GetFiles(), 
            // we get a max path length error.
            foreach (FileInfo fi in dir.GetFiles())
            {
                if (fi.Name == subpaths[subpaths.Length - 1])
                {
                    foundMatch = true;
                    break;
                }
            }
        }
    }
    // If we didn't find a match, write to the console.
    if (!foundMatch)
    {
        Console.WriteLine("   *  File: " + path + " does not exist.");
    }
}

答案 2 :(得分:5)

我自己从未遇到过这个问题,另一个SO帖子的人建议打开文件的句柄,从而首先避免整个“存在”检查。不确定这是否还有“长文件名”问题:

这是第二个答案:

Check if a file/directory exists: is there a better way?

不确定这是否有用:P

答案 3 :(得分:2)

您需要P / Invoke Win32 API才能使其正常工作:

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    static extern uint GetFileAttributes(string lpFileName);

    public static bool DirectoryExists(string path)
    {
        uint attributes = GetFileAttributes(path.StartsWith(@"\\?\") ? path : @"\\?\" + path);
        if (attributes != 0xFFFFFFFF)
        {
            return ((FileAttributes)attributes).HasFlag(FileAttributes.Directory);
        }
        else
        {
            return false;
        }
    }

    public static bool FileExists(string path)
    {
        uint attributes = GetFileAttributes(path.StartsWith(@"\\?\") ? path : @"\\?\" + path);
        if (attributes != 0xFFFFFFFF)
        {
            return !((FileAttributes)attributes).HasFlag(FileAttributes.Directory);
        }
        else
        {
            return false;
        }
    }

答案 4 :(得分:0)

检查

  1. 清单权限
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  1. 使用文件提供程序创建和访问文件
    <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="your_package.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_list" />
    </provider>
  1. 文件列表内容:
    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <external-path
            name="external"
            path="." />
        <external-files-path
            name="external_files"
            path="." />
        <cache-path
            name="cache"
            path="." />
        <external-cache-path
            name="external_cache"
            path="." />
        <files-path
            name="files"
            path="." />
    </paths>
  1. 使文件名简短