В версии 3.X: listdir, walk, glob

v versii 3 x listdir walk glob Инструменты для работы с файлами и каталогами

Поскольку в Python 3.X все обычные строки состоят из символов Юникода, имена каталогов и файлов, возвращаемые функциями os.listdir, os.walk и glob.glob, в действительности являются строками Юникода. Это может иметь некоторые последствия, если каталоги содержат необычные имена, не поддающиеся декодированию.

Формально имена файлов могут содержать любые символы, поэтому в версии 3.X функция os.listdir может работать в двух режимах: если ей передать аргумент типа bytes, она будет возвращать кодированные имена файлов в виде строк байтов; если ей передать аргумент типа str, она будет возвращать имена файлов в виде строк Юникода, декодированных в соответствии с кодировкой, используемой файловой системой:

C:\\PP4E\System\Filetools> python

>>> import os

>>> os.listdir(‘.’)[:4]

[‘bigext-tree.py’, ‘bigpy-dir.py’, ‘bigpy-path.py’, ‘bigpy-tree.py’]

>>> os.listdir(b’.’)[:4]

[b’bigext-tree.py’, b’bigpy-dir.py’, b’bigpy-path.py’, b’bigpy-tree.py’]

Версия, основанная на использовании строк байтов, может применяться для файлов с недекодируемыми именами. Функции os.walk и glob. glob за кулисами обращаются к функции os.listdir, от которой наследуют то же самое поведение. Функция os.walk обхода деревьев, например, вызывает os. listdir для каждого подкаталога — передача строки байтов в аргументе подавляет декодирование, вследствие чего в результате возвращается строка байтов:

>>> for (dir, subs, files) in os.walk(‘..’): print(dir)

..

..\Environment

..\Filetools

..\Processes

>>> for (dir, subs, files) in os.walk(b’..’): print(dir)

b’..’

b’..\\Environment’

b’..\\Filetools’

b..\\Processes

Функция glob.glob также вызывает функцию os.listdir перед применением шаблонов имен, и поэтому тоже возвращает имена в виде недеко- дированных строк байтов, когда получает строку байтов в аргументе:

>>> glob.glob(‘.\*’)[:3]

[‘.\\bigextout.txt’, ‘.\\bigexttree.py’, ‘.\\bigpydir.py’]

>>> 

>>> glob.glob(b’.\*’)[:3]

[b’.\\bigextout.txt’, b’.\\bigexttree.py’, b’.\\bigpydir.py’]

Передавая имена в виде обычных строк (например, посредством аргумента командной строки), вы можете столкнуться с необходимостью преобразовывать обычные строки в строки байтов, с целью подавить декодирование:

>>> name = ‘.’

>  >> os.listdir(name.encode())[:4]

[b’bigext-out.txt’, b’bigext-tree.py’, b’bigpy-dir.py’, b’bigpy-path.py’]

Таким образом, если каталоги могут содержать имена, не поддающиеся декодированию с использованием кодировки, используемой по умолчанию, вам может потребоваться передавать этим инструментам строки байтов, чтобы избежать ошибок, связанных с кодированием Юникода. В ответ вы будете получать строки байтов, которые могут оказаться менее читаемыми при выводе, но это убережет вас от ошибок при обходе каталогов и файлов.

Такой подход может оказаться особенно полезным в системах, где используются простейшие кодировки, такие как ASCII или Latin-1, но могут иметься файлы с именами в произвольных кодировках, скопированными с других компьютеров, из Интернета и так далее. В зависимости от ситуации для подавления некоторых ошибок кодирования можно использовать также обработчики исключений.

Пример того, какое это может иметь значение, мы увидим в первом разделе главы 6, где недекодируемое имя каталога вызывает появление ошибки при выводе во время полного сканирования диска (хотя данная ошибка относится скорее к функции вывода, чем к операции декодирования).

Обратите внимание, что встроенная функция open также может принимать имена открываемых файлов как в виде строк str Юникода, так и в виде строк байтов bytes, однако она использует этот аргумент, только чтобы дать начальное имя файлу, — порядок же обработки содержимого файла определяется дополнительным аргументом режима. Возможность передавать строку байтов в качестве имени файла позволяет использовать произвольные кодированные имена.

Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011

Оцените статью
Секреты программирования
Добавить комментарий