C# удаление папки с длинными путями

Я пытаюсь удалить папку, и удаление не удается из-за папки, содержащей длинные пути. Я предполагаю, что мне нужно использовать что-то другое вместо dir.Delete(правда), Кто-нибудь раньше проходил этот мост?

Большое спасибо

 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\ Ed\ Careers Ed\ Fun Careers Education \ Chris's не использовался 2006-2007 \ old 4. Неделя активности в области карьерного роста 1 30.10.06, 6.11.06 или 13.11.06 Знакомство с уровнями занятости и карьерными ресурсами \ Сферы деятельности и уровни занятости Справочный лист репетитора [1].doc

10 ответов

В Windows API максимальная длина пути равна MAX_PATH, которая определяется как 260 символов. Локальный путь структурирован в следующем порядке: буква диска, двоеточие, обратная косая черта, компоненты имен, разделенные обратной косой чертой, и завершающий нулевой символ. Например, максимальный путь на диске D равен "D:\some 256-символьная строка пути". <NUL> " где " <NUL> "представляет невидимый завершающий нулевой символ для текущей системной кодовой страницы. (Символы < > используются здесь для наглядности и не могут быть частью допустимой строки пути.) [MSDN]

Версии Unicode для нескольких функций допускают максимальную длину пути приблизительно 32 000 символов, состоящую из компонентов длиной до 255 символов. Чтобы указать этот тип пути, используйте "\\?\" префикс. Максимальный путь в 32 000 символов является приблизительным, потому что "\\?\" Префикс может быть расширен до более длинной строки, и расширение применяется к общей длине.

Например, "\\?\D:\<path>", Чтобы указать такой путь UNC, используйте "\\?\UNC\" префикс. Например, "\\?\UNC\<server>\<share>", Эти префиксы не используются как часть самого пути. Они указывают, что путь должен быть передан в систему с минимальной модификацией, что означает, что вы не можете использовать прямую косую черту для представления разделителей пути или точку для представления текущего каталога. Кроме того, вы не можете использовать "\\?\" префикс с относительным путем. Относительные пути ограничены символами MAX_PATH.

Оболочка и файловая система могут иметь разные требования. Можно создать путь с API, который пользовательский интерфейс оболочки не может обработать.

Синтаксис C#:

[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool DeleteFile(string path);

Для получения дополнительной информации о классе см. Системное пространство имен - MSDN

Выдержки из:

Пути файловой системы: как долго это слишком долго? - Код ужасов

Функция DeleteFile (Windows) - MSDN

Ограничение в 260 символов (я полагаю, это то, с чем вы столкнулись) является проблемой в Windows, а не в.NET, к сожалению, поэтому обойти это может быть сложно.

Вы можете обойти это, изменив свой рабочий каталог так, чтобы относительный путь для удаления был менее 260 символов; Я не знаю, сработает ли это или нет.

то есть:

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

Проверьте Win32 API: http://msdn.microsoft.com/en-us/library/aa363915%28VS.85%29.aspx

Там говорится: "В ANSI-версии этой функции имя ограничено символами MAX_PATH. Чтобы расширить этот предел до 32 767 широких символов, вызовите версию функции Unicode и добавьте"\?\"К пути".

Добавьте пинвоук:

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);
}

Лучшее, что у меня есть, это

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();
    }
}

Я не знаю, остается ли этот вопрос открытым, но я решил проблему. Код был разработан на машине win7, с VS2008. Вот шаги, которые я следовал, чтобы решить проблему

  1. Создать пустой проект VS C#
  2. Добавьте ссылку на этот COM-объект: среда выполнения сценариев Microsoft
  3. Добавить использование сценариев; к вашему списку использования
  4. Где-нибудь в вашем коде создайте функцию, похожую на эту:

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

Параметр пути - это каталог, который вы хотите удалить. Функция предваряет подпись пути Unicode, создает экземпляры FileSystemObject и удаляет путь Unicode и все его содержимое.

  • Скомпилируйте программу, запустите получившиеся файлы.exe с правами администратора (запустите от имени администратора на win7), найдите каталог, который вы хотите удалить, и примените к нему эту функцию. Затем смотрите длинные имена файлов.

Излишне говорить, что это мощно... и опасно. С большой властью приходит большая ответственность:-)

Это то, что я использую для удаления домашних каталогов, где часто встречаются длинные пути:

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) { }
}

Это похоже на решение, которое разместил Саймон, но также:

  • Уменьшает верхний предел повторов по умолчанию для robocopy.
  • Сбрасывает атрибуты как каталог
  • Создает уникальное пустое имя каталога, чтобы оно работало с несколькими потоками.

Вы можете использовать C# Apis с нотацией длинного имени файла."\\?\<driveLetter>:\..."
Это работает как сSystem.IO.File.DeleteиSystem.IO.Directory.Delete(...)

Проблема, с которой вы можете столкнуться, заключается в том, чтоDirectory.Delete(path, true)(рекурсивное удаление) не работает, за исключением того, что часть пути не может быть найдена. В этом случае убедитесь, что путь не имеет косой черты в конце и все косые черты в пути\обратная косая черта

Вы можете попробовать использовать p/invoke для получения "короткого" имени пути с помощью функции GetShortPathName из kernel32.dll:

http://www.pinvoke.net/default.aspx/kernel32.GetShortPathName

Следующая ссылка показывает внутреннюю реализацию.NET для поддержки длинных путей в System.IO, ее не так просто прочитать, как она генерируется с помощью Reflector, но содержит множество примеров работы с Win32 API, упомянутыми ранее.

http://reflector.webtropy.com/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/clr/src/BCL/System/IO/LongPath@cs/1305376/LongPath@cs

Было бы хорошо, если бы эта функциональность была доступна через System.IO, поскольку поддержка, очевидно, есть!

Я создал управляемую библиотеку.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();

ура

Другие вопросы по тегам