C # удаление папки с длинными путями - PullRequest
15 голосов
/ 08 февраля 2010

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

Ответы [ 9 ]

10 голосов
/ 08 февраля 2010

В 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

4 голосов
/ 21 октября 2010

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

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();
    }
}
3 голосов
/ 21 декабря 2011

Я не знаю, остается ли этот вопрос открытым, но я решил проблему. Код был разработан на машине 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); 
    }
    

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

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

Само собой разумеется, это мощно ... и опасно. С великой силой приходит великая ответственность :-)

3 голосов
/ 08 февраля 2010

Ограничение в 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;
2 голосов
/ 19 октября 2011

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

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.
  • Сброс атрибутов как directory.delete завершится ошибкой для всего, что помечено как доступное только для чтения.
  • Создает уникальное пустое имя каталога, чтобы оно работало с несколькими потоками.
1 голос
/ 08 февраля 2010

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

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

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

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);
}
0 голосов
/ 08 октября 2012

Я создал управляемую библиотеку .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 голосов
/ 25 февраля 2011

Следующая ссылка показывает внутреннюю реализацию .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, поскольку поддержка, очевидно, есть!

0 голосов
/ 08 февраля 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...