Получить информацию о пути из PathTooLongException - PullRequest
3 голосов
/ 06 марта 2012

Я использую DirectoryInfo и FileInfo в .Net 4.0 для перечисления файлов в дереве каталогов, и я нажимаю исключение PathTooLongException. Упрощенная версия ниже

public static class Test
{
    public static void Search(DirectoryInfo base)
    {
        foreach(var file in base.GetFiles())
        {
            try
            {
                Console.WriteLine(file.FullName);
            } catch(PathTooLongException ex)
            {
                // What path was this?
            }
        }
        foreach(var dir in base.GetDirectories())
        {
            Search(dir);
        }
    }
}

Когда выдается ошибка, я хочу знать, какой путь к файлу вызвал проблему. Очевидно, я не могу попросить FullName, потому что это ошибка. Я могу получить имя из file.Name, но если я не могу получить остальную часть пути, так как file.Directory дает PathTooLongException, хотя DirectoryInfo, из которого был найден файл, работал нормально! (Я не могу использовать это, хотя фактический код намного сложнее).

Просматривая трассировку стека, кажется, что он использует внутренний путь (я вижу защищенный file.FullPath от отладки) и пытается вырвать каталог из полного (слишком большого) пути. Похоже, что большинство проблем связано с System.IO.Path.NormalizePath, и, как я слышал, в .Net 4.0 было несколько изменений. Я не пробовал на предыдущих версиях фреймворка.

Мои вопросы:

  1. Как я могу получить полный путь из этого исключения; это, казалось бы, передается без какой-либо полезной информации.
  2. Зачем каркасу нужно ограничивать символы в пути, чтобы отрубить имя файла?

Заранее спасибо за любую помощь,
Andy

1 Ответ

6 голосов
/ 06 марта 2012

Я не могу думать ни о каком другом способе, кроме использования отражения, или использования библиотеки или P / Invoke для использования API-интерфейсов Windows, которые поддерживают длинные пути и проверяют длину вручную.Полный путь хранится в protected string поле с именем FullPath

foreach(var dir in new DirectoryInfo (@"D:\longpaths")
                     .GetFileSystemInfos("*.*", SearchOption.AllDirectories))
{
    try
    {
        Console.WriteLine(dir.FullName);
    }
    catch (PathTooLongException)
    {
                FieldInfo fld = typeof(FileSystemInfo).GetField(
                                        "FullPath", 
                                         BindingFlags.Instance | 
                                         BindingFlags.NonPublic);
                Console.WriteLine(fld.GetValue(dir));  // outputs your long path
    }
}

Если вы пытаетесь на самом деле сделать что-то с файлами, а не просто проверить длину файла, япредложил бы использовать такую ​​библиотеку от команды BCL в Microsoft , однако она не создает DirectoryInfos, FileInfo или FileSystemInfo, только строки.Так что это может быть не заменой вашего кода, как кажется.

Что касается ответа на ваш второй вопрос, я рекомендую прочитать это сообщение в блоге , посвященное длинным путям в .NET,Это цитата из нее, объясняющая, почему они так быстро не добавили поддержку длинных путей в .NET.

Мало кто жалуется на ограничение в 32 КБ, поэтому проблема решена?Не совсем.Есть несколько причин, по которым мы неохотно добавляли длинные пути в прошлом, и почему мы все еще осторожны с этим, связанные с безопасностью, непоследовательной поддержкой в ​​API-интерфейсах Windows синтаксиса \? \ И совместимостью приложений.

Это серия из 3 частей, в которой объясняется несколько причин, по которым API такой, какой он есть, и почему существуют ограничения.

...