Macos с внешней ntfs (по умолчанию только для чтения). Python os.walk не будет рекурсивно проходить через подкаталоги в ntfs
С Macbook 2021 (arm64).
uname -a
Darwin MacBook.local 21.1.0 Darwin Kernel Version 21.1.0: Wed Oct 13 17:33:01 PDT 2021; root:xnu-8019.41.5~1/RELEASE_ARM64_T6000 arm64
Внешний диск SSD2TB имеет файловую систему NTFS.
diskutil info disk4
Device Identifier: disk4
Device Node: /dev/disk4
Whole: Yes
Part of Whole: disk4
Device / Media Name: External
Volume Name: SSD2TB
Mounted: Yes
Mount Point: /Volumes/SSD2TB
Content (IOContent): None
File System Personality: NTFS
Type (Bundle): ntfs
Name (User Visible): Windows NT File System (NTFS)
Самый простой из тестов — просто сообщить имя каталога для каждого цикла, например
python3
Python 3.10.1 (main, Dec 31 2021, 10:22:35) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os, os.path
>>> os.chdir("/Volumes/SSD2TB/Photos")
>>> from glob import glob
>>> glob('*')
['Pictures']
>>> for d,dd,f in os.walk('.'): print(f"{dd}")
...
[]
>>> os.path.isdir('Pictures')
True
>>> for d, dd, f in os.walk('.'):
... print(f"{f}")
...
['.DS_Store', 'Pictures']
>>> for d, dd, f in os.walk('.'):
... print(f"{d}")
...
.
Кто-нибудь понимает, почему подкаталог в '.' сообщается как файл в os.walk(путем возврата в переменную «f»? А переменная «dd», которая должна быть списком каталогов, возвращает пустой список.
И последнее замечание. Если я попробую тот же тест по пути на локальном диске, все будет вести себя так, как ожидалось. Каталоги указываются в переменной «dd», а файлы — в «f».
Использование iterdir() из pathlib2 с is_dir() создаст список подкаталогов и файлов, например
dd = [x for x in Path(".").iterdir() if x.is_dir()]
f = [x for x in Path(".").iterdir() if x.is_file()]
Это работает с внешним диском ntfs, поэтому в os.walk что-то не хватает с macos и монтированием ntfs по умолчанию.
2 ответа
Не строго ответ, а альтернативное решение. Как я уже говорил в исходном вопросе, Path.iterdir() из pathlib работает с исходным монтированием Apple ntfs.
Итак, основываясь на этом, вот альтернатива os.walk, которая (до предела рекурсии) работает так, как должна работать os.walk.
import os, os.path, sys
from pathlib2 import Path
def pwalk(d):
d = Path(d).resolve()
dd = [ x for x in d.iterdir() if x.is_dir()]
f = [ x for x in d.iterdir() if x.is_file()]
yield (d, dd, f)
for xd in dd:
yield from pwalk( d / xd)
Итак, используя тот же случай, описанный выше,
for d, dd, f in pwalk('.'): print(f"{d}")
.
./Pictures
./Pictures/1998
./Pictures/1998/Barcelona
./Pictures/1998/Barcelona/.comments
./Pictures/2000
Теперь я установил пробную версию «NTFS для MAC» от программного обеспечения Paragon, и после нескольких проверок безопасности мой внешний диск ntfs смонтирован (R/W).
for d, dd, f in os.walk("."):
if re.match(r'.*?/\.@.*', d):
continue
print(f"{d}")
Теперь возвращает (как и ожидалось изначально) дерево каталогов из '.'.
Например
.
./Pictures
./Pictures/1998
./Pictures/1998/Barcelona
./Pictures/1998/Barcelona/.comments
./Pictures/2000
Установка ntfs-3g также может сработать, но для моего Macbook 2021 (arm64) с ОС Monterey процесс установки немного сложнее.
По крайней мере, есть решение. Но через 10 дней она будет составлять 19 долларов. Возможно, если у меня возникнет постоянная необходимость использовать диски NTFS таким образом, это будет стоить затрат, а не усилий по установке ntfs-3g.
Таким образом, настоящий виновник заключается в том, как Apple решила представить диск NTFS только для чтения и в том, как Python (os.walk) обрабатывает его.
Кстати... Я подозреваю, что музыкальный проигрыватель Strawberry также отказывался сканировать музыкальную папку на внешнем диске NTFS по тем же причинам. Это просто вернет пустую библиотеку.