连接文件名时出现UnicodeEncodeError

9 投票
4 回答
17233 浏览
提问于 2025-04-15 17:38

执行以下代码时,出现了“UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 2: ordinal not in range(128)”的错误:

filename = 'Spywaj.ttf'
print repr(filename)
>> 'Sp\xc2\x88ywaj.ttf'
filepath = os.path.join('/dirname', filename)

但是这个文件是有效的,并且在磁盘上确实存在。文件名是通过“unzip -l”命令提取的。我该如何像这样连接文件名呢?

操作系统和文件系统

Filesystem: ext3    relatime,errors=remount-ro 0       0
Locale: en_US.UTF-8

Alex的建议 现在使用os.path.join可以正常工作,但我仍然无法用它连接的文件名访问磁盘上的文件。

filename = filename.decode('utf-8')
filepath = os.path.join('/dirname', filename)
print filepath
>> /dirname/u'Sp\xc2\x88ywaj.ttf'
print os.path.isfile(filepath)
>> False

new_filepath = filepath.encode('Latin-1').encode('utf-8')
print new_filepath
>> /dirname/u'Sp\xc2\x88ywaj.ttf'
print type(filepath)
>> <type 'unicode'>
print os.path.isfile(new_filepath)
>> False

valid_filepath = glob.glob('/dirname/*.ttf')[0]
print valid_filepath
>> /dirname/Spywaj.ttf (SO cannot display the chars in filename)
print type(valid_filepath)
>> <type 'str'>
print os.path.isfile(valid_filepath)
>> True

4 个回答

2
filename = filename.decode('utf-8').encode("latin-1")
>>> os.path.isfile(filename.decode("utf8").encode("latin-1"))
True
>>>

我用这个文件 Splywaj.zip 是可以正常工作的。

7

我通过在 /etc/apache2/envvars 文件中添加这些行,并重启 Apache 服务器,解决了 UnicodeDecodeError 的问题。

export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'

具体的做法可以在这里找到: https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/modwsgi/#if-you-get-a-unicodeencodeerror

我花了一些时间来调试这个问题。

8

在拉丁字母1(ISO-8859-1)和Windows-1252编码中,0xc2代表的是一个带有抑扬符的字母A……在你展示的代码中似乎没有这个字符!能不能在

print repr(filename)

调用os.path.join之前加上一个print(同时把'/dirname'放到一个变量里,并打印它的表示形式以确保完整性)?我在想,也许那个多余的字符确实存在,但你出于某种原因没有看到它——使用repr可以揭示出来。

如果你的文件名中确实有拉丁字母1(或Windows-1252)中的非ASCII字符,你就得使用Unicode——而且根据你的操作系统和文件系统,可能还需要一些特定的编码。

编辑:提问者通过repr确认,实际上有两个字节不可能是ASCII——0xc2和0x88,对应提问者认为的一个小写字母L。这个序列在流行的UTF-8编码中是一个带有抑扬符的大写字母A(代码点0x88)——为什么提问者会觉得它像一个小写的L,真是让人费解,不过我想某些字体可能会让人产生这样的混淆。

所以我会先尝试filename = filename.decode('utf-8')——这应该能让os.path.join正常工作。如果open在处理结果的Unicode字符串时出现问题(这可能会根据文件系统和操作系统而有所不同),接下来的尝试是使用那个Unicode对象的.encode('Latin-1').encode('utf-8')。如果这些编码都不行,那么提问者尚未提供的操作系统和文件系统的信息就变得非常重要。

撰写回答