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
Выдержки из:
Пути файловой системы: как долго это слишком долго? - Код ужасов
Ограничение в 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. Вот шаги, которые я следовал, чтобы решить проблему
- Создать пустой проект VS C#
- Добавьте ссылку на этот COM-объект: среда выполнения сценариев Microsoft
- Добавить использование сценариев; к вашему списку использования
Где-нибудь в вашем коде создайте функцию, похожую на эту:
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, упомянутыми ранее.
Было бы хорошо, если бы эта функциональность была доступна через System.IO, поскольку поддержка, очевидно, есть!
Я создал управляемую библиотеку.Net для работы с файлами и папками.
var fs = LocalFileSystem.Instance : FileSystem
^^^^ место в IoC
fs.GetDirectory(@"C:\\a very very long path ...\with\subdirs\and files.txt").Delete();
ура