Python打开具有utf-8文件名的文件



在我的代码中,我使用了类似file = open(path +'/'+filename, 'wb')的东西来编写文件但在我尝试支持非ascii文件名时,我将其编码为

naming = path+'/'+filename
file = open(naming.encode('utf-8', 'surrogateescape'), 'wb')
write binary data...

因此该文件的名称类似于directory/path/xd8xb9xd8xb1xd8xa8xd9.txt它是有效的,但当我试图通过使用爬进同一目录来再次获取该文件时,问题就出现了

for file in path:
data = open(file.as_posix(), 'rb)
...

我一直收到这个错误'ascii' codec can't encode characters in position..我尝试将字符串转换为类似data = open(bytes(file.as_posix(), encoding='utf-8'), 'rb')的字节,但我得到了'utf-8' codec can't encode characters in position...'

我也尝试了file.as_posix().encode('utf-8', 'surrogateescape'),我发现编码和打印都很好,但使用open((,我仍然得到错误'utf-8' codec can't encode characters in position...'

如何打开文件名为utf-8的文件?

我在ubuntu linux 上使用Python 3.9

非常感谢您的帮助。

编辑

我弄清楚了为什么在写完之后爬到目录时会出现这个问题。因此,当我编写文件并给它原始字符串directory/path/xd8xb9xd8xb1xd8xa8xd9.txt并将该字符串编码为utf时,它写得很好。但是,当通过爬入目录再次找到文件时,str(filepath)filepath.as_posix()会将字符串返回为directory/path/????????.txt,因此当我试图将其编码到任何编解码器时,它都会给我一个错误。

目前我正在调查这个问题是否与我的linux区域设置有关,它被设置为POSIX,我将其更改为C.UTF-8,但仍然没有运气。

更多上下文:这是一个文件系统,文件通过网站上传,所以我收到utf-8格式的文件名字符串

我不明白为什么您觉得需要重新编码文件路径。

Linux(unix(文件名只是字节序列(带有几个被禁止的字节值(。没有必要在代理对中打断星体角色;星形字符的UTF-8序列在文件名中是完全可以接受的。但是创建代理项对可能会给您带来麻烦,因为代理项没有UTF-8编码。因此,如果您真的设法为代理代码点创建了类似UTF-8编码的东西,那么当您试图将其转换回Unicode代码点时,很可能会遇到解码错误。

不管怎样,没必要那么麻烦。在运行此会话之前,我创建了一个名为´ñ´的目录,其中包含两个空文件𝔐mañana。第一个是星体角色,U+1D510。正如您所看到的,一切都很好,不需要手动解码。

>>> [*Path('ñ').iterdir()]
[PosixPath('ñ/𝔐'), PosixPath('ñ/mañana')]
>>> Path.mkdir('ñ2')
>>> for path in Path('ñ').iterdir():
...   open(Path('ñ2', path.name), 'w').close()
...
>>> [*Path('ñ2').iterdir()]
[PosixPath('ñ2/𝔐'), PosixPath('ñ2/mañana')]
>>> [open(path).read() for path in Path('ñ2').iterdir()] 
['', '']

注意:

OP在评论中表示,他们之前曾尝试过:

file = open('/upload/xd8xb9xd8xb1xd8xa8xd9x8a.png', 'wb')

并接收到错误

UnicodeEncodeError: 'ascii' codec can't encode characters in position 8-11: ordinal not in range(128)

如果没有更多的细节,很难知道如何回应。对于不允许使用非ascii字符的文件系统,open可能会引发该错误,但这在Linux上是不正常的。

然而,值得注意的是字符串文字

'/upload/xd8xb9xd8xb1xd8xa8xd9x8a.png'

不是您认为的字符串。Python字符串中的x转义符是Unicode代码点(最大值为255(,而不是单个UTF-8字节值。Python字符串文字"xd8xb9"包含两个字符;O带有笔划";(Ø(和";上标1";(¹(;换句话说,它与字符串文字"u00d8u00b9"完全相同。

要获得阿拉伯字母ain(ع(,只需键入它(如果您有阿拉伯键盘设置,并且源文件编码为UTF-8,这是默认值(,或者对其代码点U+0639:"u0639"使用Unicode转义。

如果出于某种原因,您坚持使用显式UTF-8字节编码,则可以使用byte文字作为open:的参数

file = open(b'/upload/xd8xb9xd8xb1xd8xa8xd9x8a.png', 'wb')

但不建议这样做。

因此,在过去几天陷入兔子洞之后,我认为问题不在于python本身,而在于我的web框架使用的区域设置。调试这个,我看到

import sys
print(sys.getfilesystemencoding())

返回"ASCII",这很奇怪,因为我已经将linux区域设置为C.UTF-8,但由于我在Apache2上运行WSGI,我不得不在Apache配置文件中添加区域设置,如WSGIDaemonProcess my_app locale='C.UTF-8'

最新更新