Получить информацию о пути из PathTooLongException

Я использую 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. Зачем фреймворку нужно ограничивать символы в пути, чтобы отрубить имя файла?

Заранее благодарю за любую помощь,
Энди

1 ответ

Решение

Я не могу думать ни о каком другом способе, кроме использования отражения или использования библиотеки или 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.

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

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

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