在Windows环境中管理带有非ASCII字符的Mac OS文件名?

5

我处理大量未知文件集,一直在学习Python来帮助我筛选/排序和处理这些文件。

我正在查看的一个集合有大量的资源叉,我编写了一个小脚本来查找它们并删除它们(下一步是查找它们并将它们移动,但那是另一天的事情)。

我在这个集合中发现有许多文件名中包含非ascii字符,这似乎使os.delete函数无法正常工作。

例如文件名:._spec com report 395 (注:3下面有一个小点,我找不到例子,也不知道如何显示文件名的十六进制...)

我记录了所有的文件名,这是那个文件的记录:._spec com报告3?95

我得到的错误是一个WindowsError,因为它找不到文件(它传递的字符串不是Windows OS所知道的文件名)。我放了一个try语句来解决问题,但我真的想妥善处理它。

我还尝试使用遍历选项中的unicode开关`os.walk(u'。')`,如此帖子所述:处理Python字符串中的ASCII字符(置顶答案),然后我看到以下错误:

Traceback (most recent call last):
 File "<stdin>", line 3, in <module>
 File "c:\python27\lib\encodings\cp850.py", line 12, in encode
    return codecs.charmap_encode(input,errors,encoding_map)
UnicodeEncodeError: 'charmap' codec can't encode character u'\uf022' in position
20: character maps to <undefined>

我猜答案在于文件名的解析方式,想知道是否有人能够指点一下我正确的方向...
代码:
import os
import sys

rootdir = "c:\target Dir to walk"
destKeep = "Keepers.txt"
destDelete = "Deleted.txt"

matchingText = "._"
files_removed = 1
for folder, subs, files in os.walk(rootdir):  
    outfileKeep = open(destKeep,"a")
    outfileDelete = open(destDelete,"a")
    for filename in files:
        matchScore = filename.find(matchingText)
        src = os.path.join(folder, filename)
        srcNewline = src + ", " + str(filename) + "\n"
        if matchScore == -1:
        outfileKeep.writelines(srcNewline)
        else: 
            outfileDelete.writelines(srcNewline)
            try:
                os.remove(src)
        except WindowsError:
                print "I was unable to delete this file:"
                outfileKeep.writelines(srcNewline)
            files_removed += 1
            if files_removed:
                print '%d files removed' % files_removed
            else :
                print 'No files removed'
    outfileKeep.close()
    outfileDelete.close()
1个回答

3

os.walk(u'.') 是获取本地Unicode文件名的常规方式,它应该可以正常工作;对我来说确实如此。

你的问题在这里:

srcNewline = src + ", " + str(filename) + "\n"
str(filename) 将使用默认编码将您的Unicode字符串转换回字节,因为该编码不具有字符U+F022(*),所以会出现UnicodeEncodeError。您需要选择要在输出文件中存储的编码,例如通过执行 srcNewLine= '%s, %s\n' % (src, filename.encode('utf-8')),或者(也许更好)保持字符串为Unicode并使用codecs.open打开文件写入它们。 (*:这是一个私用区字符,不应该被使用,但现在你也无能为力...)

嗨,感谢回复。我理解你所说的大部分内容,并一直在尝试你的建议。我仍然无法让它工作 - 而且我认为我更接近了解问题...... 问题似乎是操作系统层如何处理文件名,这与基于MSDOS的功能处理文件名的方式不同。基本上,在文件名中有一个两个字节的字符(未知编码),资源管理器可以“看到”它,但在MSDOS中会被剥离和屏蔽。看来传递这个字符是问题所在 - 也许我应该查看位流而不是字符串? - Jay
我还发现所涉及的字形由ASCII数字组成,后跟EF 80 A2的十六进制代码。我通过在Firefox中查看文件夹并查看源代码来发现这一点。有趣的是,我可以看到几个数字的数字字形,每个数字都带有相同的后续代码,这表明字符的长度为4个字节 - UTF-16? - Jay
字节序列 EF 80 A2 是 U+F022 的 UTF-8 编码。这就是我期望 .encode('utf-8') 在输出到 Keepers.txt/Deleted.txt 文件时的工作方式,所以没问题。但是你不应该使用编码为字节的字符串来实际访问文件,因为当你使用字节字符串作为文件名时,你只能使用系统默认代码页(其中大多数 Unicode 字符都没有,当然也没有虚假的 U+F022 字符)。将文件名保留为 Unicode,只在写入字节流时将它们编码为字节。 - bobince
太棒了,谢谢你。我在U+F022字形和音标方面做了很多背景阅读。这一切都非常合理。感谢你的时间,我非常感激。 :) - Jay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接