C#删除具有长路径的文件夹

17

我正在尝试删除一个文件夹,但是由于该文件夹包含了很长的路径,所以无法删除成功。我猜测我需要使用其他方法而不是dir.Delete(true)。有人之前解决过这个问题吗?

非常感谢。

 try
{
 var dir = new DirectoryInfo(@FolderPath);
 dir.Attributes = dir.Attributes & ~FileAttributes.ReadOnly;
 dir.Delete(true);
}
catch (IOException ex)
{
 MessageBox.Show(ex.Message);
}

这就是有问题的路径:\server\share\dave\Private\Careers\Careers Ed\Fun Careers Education\Chris's not used 2006 to07\old 4.Careers Area Activity Week 1 30.10.06 or 6.11.06 or 13.11.06 Introduction to job levels and careers resources\Occupational Areas & Job levels Tutor Help Sheet[1].doc


路径有多长: http://www.codinghorror.com/blog/archives/000729.html - James Campbell
你尝试过使用Unicode路径调用win32函数吗? - sclarson
10个回答

13
在Windows API中,路径的最大长度为MAX_PATH,定义为260个字符。本地路径的结构顺序如下:驱动器号、冒号、反斜杠、由反斜杠分隔的名称组件和终止的空字符。例如,在D盘上的最大路径是“D:\some 256-character path string”,其中“”代表当前系统代码页的不可见终止空字符。(此处使用“<”和“>”字符只是为了视觉清晰,不能成为有效路径字符串的一部分。)[MSDN] 若要指定最长可以达到大约32,000个字符且由长度最多为255个字符的组件组成的路径,请使用几个函数的Unicode版本。为了指定这种类型的路径,请使用"\\?\"前缀。32,000个字符的最大路径是近似值,因为"\\?\"前缀可以扩展为更长的字符串,并且扩展适用于总长度。
例如,"\\?\D:\<path>"。要指定这种 UNC 路径,请使用前缀 "\\?\UNC\"。例如,"\\?\UNC\<server>\<share>"。这些前缀不作为路径本身的一部分使用。它们表示应将路径传递给系统时进行最小修改,这意味着您不能使用正斜杠来表示路径分隔符,也不能使用句点来表示当前目录。此外,您不能在相对路径中使用前缀 "\\?\"。相对路径限制为 MAX_PATH 字符。
Shell 和文件系统可能具有不同的要求。可以使用 API 创建无法处理的 shell UI 路径。
C# 语法:
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool DeleteFile(string path);

有关该类的更多信息,请参见System Namespace - MSDN

摘自:

文件系统路径:多长才算太长?- Coding Horror

DeleteFile函数(Windows)- MSDN


1
嗨,我刚试了一下,但是我得到了同样的错误信息:“找不到路径 '长路径和文件名' 的一部分”。你知道还有什么其他方法可以尝试吗?谢谢 - Jamie
这个可行,我试过了,对于我来说使用长达300个字符的路径也是有效的。 - James Campbell

4

我猜您遇到的问题是Windows系统中260字符的限制,这不幸地不是.NET的问题,因此解决起来可能会很困难。

可能通过更改工作目录使得删除的相对路径小于260个字符来解决它,但我不确定是否可行。

例如:

var curDir = Directory.GetCurrentDirectory();
Environment.CurrentDirectory = @"C:\Part\Of\The\Really\Long\Path";
Directory.Delete(@"Relative\Path\To\Directory");
Environment.CurrentDirectory = curDir;

1
你在Directory.Delete("相对路径\到\目录")中缺少一个@符号。 - Simon

4
请查看Win32 API:http://msdn.microsoft.com/en-us/library/aa363915%28VS.85%29.aspx 其中指出:“在此函数的ANSI版本中,名称限制为MAX_PATH个字符。要将此限制扩展到32,767个宽字符,请调用该函数的Unicode版本并在路径前面添加"\?\"。”
请添加pinvoke:
using System;  
using System.Runtime.InteropServices;  
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]  
[return: MarshalAs(UnmanagedType.Bool)]  
internal static extern bool DeleteFile(string lpFileName);

使用方法:
public static void DeleteLong(string fileName) {

    string LongName = @"\\?\" + fileName;
    DeleteFile(formattedName);
}

从Windows 10版本1607开始,对于此函数的Unicode版本(DeleteFileW),您可以选择加入以删除MAX_PATH字符限制,而无需在前面添加“\?\”。有关详细信息,请参阅“命名文件、路径和命名空间”的“最大路径限制”部分。 - JJS
DeleteFile() API 适用于文件而非目录。正确的 API 是 RemoveDirectory() - linuxuser27

4
我目前最好的翻译是这个。
public static class IOHelper
{
    public static void DeleteDirectory(DirectoryInfo directoryInfo)
    {
        var emptyTempDirectory = new DirectoryInfo(Path.Combine(Path.GetTempPath(), "IOHelperEmptyDirectory"));
        emptyTempDirectory.Create();
        var arguments = string.Format("\"{0}\" \"{1}\" /MIR", emptyTempDirectory.FullName, directoryInfo.FullName);
        using (var process = Process.Start(new ProcessStartInfo("robocopy")
                                            {
                                                Arguments = arguments,
                                                CreateNoWindow = true,
                                                UseShellExecute = false,
                                            }))
        {
            process.WaitForExit();
        }
        directoryInfo.Delete();
    }
}

如果您能解释一下什么是robocopy以及为什么要使用/MIR,那就太好了。 - Vinicius Rocha
此外,这并不适用于所有情况 - 因为它在我的情况下并没有起作用。Robocopy的“MIR”或“PURGE”选项都无法解决问题。重命名为<260,或迭代驱动器安装也无效。我尝试了2000个级别后放弃了。 - thepip3r

3

我不知道这个问题是否还有待解决,但是我已经解决了。代码是在一台Windows 7电脑上使用VS2008开发的。以下是我解决问题时采取的步骤:

  1. Create an empty VS C# project
  2. Add a reference to this COM Object: microsoft scripting runtime
  3. Add a using Scripting; to your using list
  4. Somewhere in your code, create a function resembling this:

    private static void DeletePathWithLongFileNames(string path)
    {
        var tmpPath = @"\\?\"+ path
        FileSystemObject fso = new FileSystemObjectClass() as FileSystemObject;
        fso.DeleteFolder(tmpPath, true); 
    }
    

路径参数是您要删除的目录。该函数会添加Unicode路径签名,创建FileSystemObject实例并删除Unicode路径及其所有内容。

  • 编译程序,以管理员权限运行生成的.exe文件(在Win7上作为管理员运行),查找要删除的目录并对其应用此函数。然后,观察长文件名消失。

不用说,它很强大...也很危险。伟大的力量带来伟大的责任 :-)


2

这是我用于删除主目录的方法,其中经常出现长路径:

public static void DirectoryDeleteLong(string directoryPath)
{
    var emptyDirectory = new DirectoryInfo(Path.GetTempPath() + "\\TempEmptyDirectory-" + Guid.NewGuid());
    try
    {
        emptyDirectory.Create();
        using (var process = new Process())
        {
            process.StartInfo.FileName = "robocopy.exe";
            process.StartInfo.Arguments = "\"" + emptyDirectory.FullName + "\" \"" + directoryPath + "\" /mir /r:1 /w:1 /np /xj /sl";
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.CreateNoWindow = true;
            process.Start();
            process.WaitForExit();
        }
        emptyDirectory.Delete();
        new DirectoryInfo(directoryPath).Attributes = FileAttributes.Normal;
        Directory.Delete(directoryPath);
    }
    catch(IOException) { }
}

这个解决方案与Simon发布的类似,但也:

  • 减少了robocopy默认的重试次数限制。
  • 重置属性,因为directory.delete将无法删除任何标记为只读的文件。
  • 创建一个独特的空目录名称,以便它可以与多线程一起使用。

0
你可以使用C#的API来处理长文件名,使用的表示方法是"\\?\<driveLetter>:\..."。这个方法适用于System.IO.File.DeleteSystem.IO.Directory.Delete(...)
可能会遇到的问题是,Directory.Delete(path, true)(递归删除)在路径的一部分找不到的情况下无法正常工作。在这种情况下,请确保路径末尾没有斜杠,并且路径中的所有斜杠都是\反斜杠。

0

0
我创建了一个托管的 .Net 库来处理文件和文件夹。

https://github.com/DotNetIO

var fs = LocalFileSystem.Instance : FileSystem

^^^^ 放置在IoC中

fs.GetDirectory(@"C:\\a very very long path ...\with\subdirs\and files.txt").Delete();

干杯


0

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