ошибка pathlib Path.rglob при длинных путях к файлам в Windows

#python #python-3.x #path #pathlib

#python #python-3.x #путь #pathlib

Вопрос:

Я пытаюсь вернуть список всех файлов и вложенных папок в определенном месте. Мой код выглядит следующим образом:

 from pathlib import Path
FOLDER_PATH = Path(r'C:longfilepathof138characters')
  

Я получаю ошибку:
FileNotFoundError: [WinError 3] The system cannot find the path specified:

Ошибка возникает в пути к папке, а не в файле, поэтому я не уверен, может ли это быть причиной.

Когда я захожу в папку вручную и пытаюсь открыть PDF там, я получаю «Произошла ошибка при открытии этого документа. Этот файл не может быть найден.»

Аналогично, когда я пытаюсь открыть XLSX файл, я получаю сообщение «К этому файлу невозможно получить доступ. Попробуйте одно из следующих действий: (убедитесь, что оно существует, не доступно только для чтения, не превышает 218 символов и т.д.)»

Пути к файлам в этой папке, безусловно, содержат более 218 символов, что, как я понимаю, может быть проблемой для Excel, но я не понимаю, почему это было бы проблемой для pathlib.Path.rglob их перечисления, кто-нибудь это понимает?

Однако, если я использую CMD ( dir /s /b > files.txt ), я могу получить список.

Кроме того, если я затем импортирую files.txt в список Path объектов paths на python и попытаюсь выполнить [x.is_file() for x in paths] , он не будет правильно идентифицировать некоторые из более длинных путей как файлы.

Я проверил, что если я скопирую каталог локально (где существует гораздо более короткий путь), то файлы будут доступны с помощью Excel и pathlib.Path.rglob .

Что можно сделать, чтобы обойти эту проблему, и почему это проблема в первую очередь?

Комментарии:

1. В документации Microsoft говорится, что максимальная длина пути для большинства функций в Windows API составляет 260 символов.

Ответ №1:

Проблема в том, что большинство функций файловой системы Windows не принимают пути, которые выглядят как:

 r'C:longfilepathof256characters'
  

Таким образом, pathlib и Excel обнаруживают, что они не могут открыть файл или прочитать каталог, используя эти функции Windows.

Хорошей новостью является то, что функции Windows принимают пути, которые выглядят как:

 r'\?C:longfilepathof256characters'
  

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

 >>> Path(r'\?foo').joinpath(r'\?bar')
WindowsPath('//?/foo/bar')  # correct
>>> Path(r'\?foo', r'\?bar')
WindowsPath('//?/bar')  # incorrect
>>> Path(r'\?c:foo').joinpath(r'c:bar')
WindowsPath('c:/bar')  # correct, but not the result we want
  

Другая плохая новость заключается в том, что такие пути несколько ограничены: когда путь, ведущий к функции файловой системы Windows, начинается с \? , вы не можете использовать косые черты или одинарные или двойные точки.

Хорошей новостью является то, что функция, подобная следующей, преобразует практически любой беспорядочный путь, который вы придумали, во что-то, что работает:

 def longname(path):
    return pathlib.Path('\\?\'   os.fspath(path.resolve()))
  

Помните, что resolve() удаляет \? только с начала, path если path действительно существует, поэтому приведенный выше код не работает в случае, когда path не существует и уже есть \? . Итак, либо убедитесь, что ваша программа использует «обычные» пути без префикса и вызывает longname() в последнюю очередь перед выполнением каких-либо реальных файловых операций, либо улучшите longname() :

 def longname(path):
    normalized = os.fspath(path.resolve())
    if not normalized.startswith('\\?\'):
        normalized = '\\?\'   normalized
    return pathlib.Path(normalized)
  

Поведение Windows задокументировано Microsoft: https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation

Комментарии:

1. Из ссылки, которой вы поделились, кажется, что точки и двойные точки принимаются как часть имен файлов (например, file..txt ), просто не интерпретируются как относительные пути, как в ..file.txt .

2. Можем ли мы настроить это так, чтобы оно работало в Windows и Linux? 🙂