Python的os.stat和unicode文件名

16
在我的Django应用程序中,用户上传了一个文件,文件名中包含Unicode字符。当我下载文件时,我调用的是:
os.path.exists(media)

为了测试文件是否存在。这反过来似乎调用了

st = os.stat(path)

接下来会出现以下错误:

UnicodeEncodeError: 'ascii'编解码器无法在位置92处编码字符u'\xcf':超出范围(128)

我能做些什么来处理这个问题?是否有一种方法可以让path.exists处理它?

更新:实际上,我所要做的就是对exists的参数进行编码,例如:

os.path.exists(media.encode('utf-8')

感谢回答的每一位。


2
你的解决方案存在问题,就是它不具备可移植性。os.path.exists 应该根据操作系统的区域设置自动处理编码。 - Martin Konecny
5个回答

9
我假设您正在使用Unix系统。如果不是,请记得说明您所在的操作系统。
确保您的语言环境设置为UTF-8。现代Linux系统通常默认设置环境变量LANG为“en_US.UTF-8”或其他语言。此外,请确保您的文件名以UTF-8编码。
有了这个设置,即使在Python 2.x中,访问任何语言的文件也无需处理编码问题。
[~/test] echo $LANG
en_US.UTF-8
[~/test] echo testing > 漢字
[~/test] python2.6
Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.stat("漢字")
posix.stat_result(st_mode=33188, st_ino=548583333L, st_dev=2049L, st_nlink=1, st_uid=1000, st_gid=1000, st_size=8L, st_atime=1263634240, st_mtime=1263634230, st_ctime=1263634230)
>>> os.stat(u"漢字")
posix.stat_result(st_mode=33188, st_ino=548583333L, st_dev=2049L, st_nlink=1, st_uid=1000, st_gid=1000, st_size=8L, st_atime=1263634240, st_mtime=1263634230, st_ctime=1263634230)
>>> open("漢字").read()
'testing\n'
>>> open(u"漢字").read()
'testing\n'

如果这不起作用,请运行“locale”命令;如果值为“C”而不是en_US.UTF-8,则可能未正确安装区域设置。
如果您使用的是Windows操作系统,我认为Unicode文件名应该总是可以正常工作的(至少对于os/posix模块来说),因为Windows中的Unicode文件API是透明支持的。

3
我尝试在控制台中使用相同的字母 ß,它可以正常工作,但是当我在脚本中执行时就不行了,会出现 IOError,显示没有该文件或目录,并且这个字符已经被编码为 '\xc3\x9f'。 - chuse

6

以上这些解决方案都对我没有用。然而,我找到了一个解决方案。如果使用 WSGI,则还需要在 Apache 设置的另一个位置添加区域设置。 官方文档在这里。请在以下位置添加以下两行代码到/etc/apache2/envvars(在 Ubuntu 上):

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

然后重启服务器。这样解决了我的问题。


2

当从Upstart运行服务(例如:gunicorn)时,很容易出现这种错误。

为了解决这个问题,在upstart文件中设置env:

env LANG=en_US.UTF-8
env LC_CTYPE=en_US.UTF-8
env LC_ALL=en_US.UTF-8

1

在调用之前将编码转换为文件系统编码。请参考locale模块。


谢谢你。但我不确定我理解了。您是说我可以告诉Django要调整上传文件的名称吗?我在locale模块中没有看到任何相关内容。 - interstar
2
你必须使用本地系统的编码来引用文件。尝试使用 locale.nl_langinfo(locale.CODESET) - Ignacio Vazquez-Abrams

1
将您的http服务器更改为使用UTF-8语言环境。例如,我在CentOS上使用apache2。我通过HTTPD_LANG更改了/etc/sysconfig/httpd语言环境设置。
# CentOS use /etc/sysconfig/httpd to config environment variables.
#
# By default, the httpd process is started in the C locale; to
# change the locale in which the server runs, the HTTPD_LANG
# variable can be set.
#
# HTTPD_LANG=C
HTTPD_LANG=en_US.UTF-8  # you can change to your locale.

这对我没有影响(Django 1.10,在Ubuntu 16.04上运行)。我仍然会收到错误信息,而且我不能使用OP的解决方案,因为我没有执行“os.path”调用,是Django在执行。 - CoderGuy123
Apache配置可能取决于您使用的操作系统类型。Ubuntu可能会使用不同的路径。 - Ming C

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