配备 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”中报告。
使用 pathlib2 的 iterdir() 与 '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 的默认挂载中缺少某些内容。
答案1
我现在已经安装了 Paragon 软件的“NTFS for MAC”试用版,在经过一些安全检查后,我的外部 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 也可能有效,但对于我的搭载操作系统“Monterey”的 Macbook 2021 (arm64) 来说,安装过程稍微复杂一些。
至少有解决方案。但 10 天后,费用将达到 19 美元。如果我继续需要以这种方式使用 NTFS 驱动器,那么与费力安装 ntfs-3g 相比,这笔费用可能值得。
因此,真正的罪魁祸首在于 Apple 选择呈现只读 NTFS 驱动器的方式以及 Python(os.walk)处理它的方式。
顺便说一句...我怀疑“Strawberry”音乐播放器也因为同样的原因拒绝扫描外部 NTFS 驱动器上的音乐文件夹。它只会返回一个空白库。
答案2
严格来说,这不是答案,而是一种替代解决方案。正如我在原始问题中所说,pathlib 的 Path.iterdir() 确实可以与原始 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