如何在Python中处理无法解码的文件名?

9 投票
2 回答
1963 浏览
提问于 2025-04-16 02:19

我希望我的Python应用程序内部只处理Unicode字符串。最近这方面进展不错,但我在处理路径时遇到了一些问题。POSIX文件系统的API不支持Unicode,所以有可能(而且其实还挺常见的)出现一些“无法解码”的文件名:这些文件名并不是按照文件系统所说的编码来编码的。

在Python中,这种情况表现为从os.listdir()返回的对象混合了unicodestr

>>> os.listdir(u'/path/to/foo')
[u'bar', 'b\xe1z']

在这个例子中,字符'\xe1'是用Latin-1编码的,即使这个(假设的)文件系统报告sys.getfilesystemencoding() == 'UTF-8'(在UTF-8中,这个字符会被编码为两个字节'\xc3\xa1')。因此,如果你尝试用Unicode路径,比如使用os.path.join(),就会到处遇到UnicodeError,因为文件名无法解码。

Python Unicode HOWTO对Unicode路径名提供了这样的建议:

请注意,在大多数情况下,应该使用Unicode API。字节API只应在可能存在无法解码的文件名的系统上使用,也就是Unix系统。

因为我主要关注Unix系统,这是否意味着我应该重构我的程序,只用字节字符串来处理路径?(如果是这样,我该如何保持与Windows的兼容性?)或者有没有其他更好的方法来处理无法解码的文件名?在实际使用中它们是否稀少到我可以直接要求用户重命名文件?

(如果最好是内部只处理字节字符串,我还有一个后续问题:如何在SQLite中存储一个列的字节字符串,同时保持其他数据为友好的Unicode字符串?)

2 个回答

2

如果你需要在一个支持UNICODE的数据库里存储字节字符串,那么把字节字符串转换成十六进制格式存储会更简单。这样,十六进制编码的字符串就可以安全地作为UNICODE字符串存储在数据库里。

关于UNIX路径名的问题,我了解到文件名并没有强制要求特定的编码,所以不同的文件可以使用不同的编码,比如Latin-1、KOI-8-R、CP1252等。这意味着路径中的每个部分都可以有不同的编码。

我会尝试用一些工具,比如chardet模块,来猜测文件名的编码。当然,这并没有保证,所以你还是需要处理一些异常情况,但这样可以减少无法解码的文件名。有些软件会把无法解码的字符替换成问号(?),这就无法恢复了。我更希望看到它们被替换成类似于\xdd或\xdddd的形式,因为这样如果需要的话,可以手动恢复。在某些应用中,可能可以把字符串展示给用户,让他们输入UNICODE字符来替换那些无法编码的字符。

如果你选择这个方法,可能需要对chardet进行扩展来完成这个工作。最好能有一个工具,扫描文件系统,找到那些无法解码的文件名,并生成一个可以编辑的列表,然后再反馈回去,修复所有与UNICODE对应的文件名。

5

如果你愿意使用Python 3.1或更高版本,Python其实有办法解决这个问题。

你可以查看这个链接了解更多信息:PEP 383 - 系统字符接口中的不可解码字节

撰写回答