用户上传一个压缩文件(内含 html 文件夹),网站解压文件并保存至指定目录,供外部直接访问静态 html 文件。
解压文件时报错:UnicodeEncodeError: 'ascii' codec can't encode characters,具体信息见链接:报错信息
def handle_uploaded_file(f, num, new_dir_name):
release_file_dir = os.path.join(UPLOAD_FILES_DIR, str(num))
new_dir = os.path.join(release_file_dir,new_dir_name)
filePath = f
with zipfile.ZipFile(filePath, 'r') as zf:
for fn in zf.namelist():
right_fn = fn.encode('cp437').decode('utf-8') # 将文件名正确编码
right_fn = os.path.join(release_file_dir, right_fn)
if right_fn[-1] == '/':
os.makedirs(right_fn, mode=0o777) #创建文件夹
continue
with codecs.open(right_fn, 'w+', encoding='utf-8') as output_file: # 创建并打开新文件
with zf.open(fn, 'r') as origin_file: # 打开原文件
shutil.copyfileobj(origin_file, output_file) # 将原文件内容复制到新文件
renameFile(release_file_dir,new_dir)
return os.path.join(release_file_dir,new_dir_name)```
1
golmic 2018-06-26 12:42:25 +08:00 via Android
服务器的 python 版本是? Python 解压用的哪个库?我没理解错需求吧,就是程序解压 zip 的时候出的错
|
2
watermelon92 OP @golmic python3.4 解压用的 zipfile
|
3
1130335361 2018-06-26 12:55:46 +08:00
用的是 apache 还是 nginx,我之前 django 配合 apache 的时候出现过这个问题
|
4
watermelon92 OP @1130335361 用的 Nginx 加 gunicorn,你之前也是到服务器上才报错吗?
|
5
golmic 2018-06-26 13:02:00 +08:00 via Android 1
服务器上手动跑一下解压的函数,贴一下报错信息
|
6
1130335361 2018-06-26 13:10:14 +08:00
@watermelon92 是的,改了 apache 的的环境变量才行的
|
7
1130335361 2018-06-26 13:14:47 +08:00
|
8
1130335361 2018-06-26 13:16:19 +08:00 1
@watermelon92 拉到最底部有说“ Fixing UnicodeEncodeError for file uploads ”这个错误的解决办法,https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/uwsgi/
|
9
watermelon92 OP @golmic 好的,我稍后试下。谢谢!
|
10
watermelon92 OP @1130335361 我用的是 gunicorn,好像没写过 uwsgi.ini 文件。。
|
11
v1v 2018-06-26 13:47:46 +08:00 1
以前 centos 也出现这个问题, 改 /etc/sysconfig/i18n,
设置 LANG=en_US.UTF-8 , 重启服务器就好了 |
12
watermelon92 OP em...我的 ubuntu 系统没有 sysconfig 文件夹
|
13
watermelon92 OP @v1v 这是现在 locale 的结果:
LANG=en_US.utf8 LANGUAGE= LC_CTYPE="en_US.utf8" LC_NUMERIC="en_US.utf8" LC_TIME="en_US.utf8" LC_COLLATE="en_US.utf8" LC_MONETARY="en_US.utf8" LC_MESSAGES="en_US.utf8" LC_PAPER="en_US.utf8" LC_NAME="en_US.utf8" LC_ADDRESS="en_US.utf8" LC_TELEPHONE="en_US.utf8" LC_MEASUREMENT="en_US.utf8" LC_IDENTIFICATION="en_US.utf8" LC_ALL= |
14
freakxx 2018-06-26 14:20:11 +08:00
@watermelon92
直接去到 21 行 log 下看名字变成了什么; 确定编码问题后再往上处理 楼上说的解决办法 如果是 uwsgi + nginx 这一套,直接再 uwsgi 指定 LANG 就可以了。 |
15
lxy42 2018-06-26 14:24:21 +08:00
right_fn = fn.encode('cp437').decode('utf-8') # 将文件名正确编码
这里为什么需要对 fn 进行 encode 和 decode ? fn 如果可以 encode 的话,说明 fn 是 unicode 类型,就没必要先 encode 在 decode 了(最终结果还是 unicode ) 而且 encode 和 decode 的编码参数都不一致,可能会导致异常。 说回你的问题,我猜测是 `right_fn = os.path.join(release_file_dir, right_fn)` 导致`right_fn`编码出问题了,建议你检查一下`release_file_dir` 和 `right_fn ` 的编码。 |
16
watermelon92 OP debug 信息里,文件名是对的。因为 zipfile 解压是默认用‘ cp437 ’ decode 的,所以我先做了解压文件的名称处理。得到正确的文件名后,用 open()函数基于解压后的文件名创建文件的。目前就是提示在这个 open()函数上出错了。但我在服务器端直接运行同样的函数是可以正常创建文件的。
|
17
watermelon92 OP |
18
watermelon92 OP |
19
glasslion 2018-06-26 15:05:47 +08:00 1
|
20
freakxx 2018-06-26 15:12:37 +08:00
$LANG
|
21
freakxx 2018-06-26 15:14:22 +08:00 1
|
22
lxy42 2018-06-26 15:19:12 +08:00 1
@watermelon92 #18
right_fn 编码没问题,那可能是文件系统编码默认是 ascii 的问题,你看一下 sys.getfilesystemencoding()是什么。 如果是 ascii 的话, 1. 设置正确的 locale 或者 2. 将 right_fn 编码为 bytes: right_fn = right_fn.encode(ENCODING) with codecs.open(right_fn, 'w+', encoding='utf-8') as output_file: # 创建并打开新文件 |
23
Tzen 2018-06-26 15:20:23 +08:00
之前遇到过这个问题,我用 supervisor 管理的进程,配置里更改环境变量就好;
我项目里是这么加的:environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8 |
24
copie 2018-06-26 15:39:19 +08:00 via Android
这个属于系统编码的问题。我用 docker 发布的时候如下解决的。
echo "zh_CN.UTF-8 UTF-8" > /etc/locale.gen locale-gen ENV LANG=zh_CN.UTF-8 |
25
copie 2018-06-26 15:39:57 +08:00 via Android 1
这个属于系统编码的问题。我用 docker 发布的时候如下解决的。
RUN echo "zh_CN.UTF-8 UTF-8" > /etc/locale.gen RUN locale-gen ENV LANG=zh_CN.UTF-8 |
26
robinlovemaggie 2018-06-26 15:46:04 +08:00 1
把字符乱码问题归结系统语言设置上是不可取的,这本身不符合 KISS 原则的。
问题可能处在你的开发环境里“ cp437 ”字符编码不能和目标服务器兼容,处理这部分就好了,放弃修改服务器系统设置。 |
27
freakxx 2018-06-26 15:55:24 +08:00
@watermelon92
@copie 尽量像 @robinlovemaggie 说的, 不要去动系统层面的配置 如果是用 uwsgi 那么就在里面指定 LANG 如果是用 supervisor 也在里面像 @Tzen 说的,设置下 |
28
robinlovemaggie 2018-06-26 16:02:36 +08:00
|
29
watermelon92 OP |
30
robinlovemaggie 2018-06-26 16:35:03 +08:00
@watermelon92 来自 wiki 关于 codepage437 的解释:
Code page 437 is the character set of the original IBM PC (personal computer), or MS-DOS. It is also known as CP437, OEM 437, PC-8, or MS-DOS Latin US. The set includes ASCII codes 32 – 126, extended codes for accented letters (diacritics), some Greek letters, icons, and line-drawing symbols. |
31
copie 2018-06-26 19:50:12 +08:00 via Android
@robinlovemaggie 但是通过配置 Python 启动的环境变量确实可以成功运行。但是如果有一天代码上线后出现问题远程打开代码注释都是乱码。log 汉字这是乱码岂不是更加的闹心。
|
32
tlday 2018-06-27 00:11:42 +08:00 via iPhone 1
呃,我没看懂你们在说啥,但是,同样是 zip 文件,在 Windows 下和 Unix 下,文件名的编码是有差异的,这个是 zip 文件标准没有覆盖文件名编码方式的问题,应该从这个方向着手。修改系统编码方式是不可取的。
|
33
tlday 2018-06-27 00:18:02 +08:00 via iPhone
你的注释打开原文件的这一行好像也没有指定打开文件的编码方式,然后把原文件复制到新文件如果编码不同,是可以直接复制的吗…不需要 decode,encode 吗?我在 python 解决编码问题方面是个菜鸡,只是提供下思路。
|
34
tlday 2018-06-27 00:29:29 +08:00 via iPhone
感觉自己没仔细看回复闹了乌龙
|
35
robinlovemaggie 2018-06-27 09:40:51 +08:00
@copie 远程汉字乱码可以改一下 ssh 工具的传输编码就行了
|
36
watermelon92 OP @golmic
我在服务器上单独运行了,成功解压没有报错。 demo 代码见下: import os,shutil import zipfile filePath = '/Users/dylan/Desktop/3.2.zip' release_file_dir = '/Users/dylan/Desktop/testunzip3' with zipfile.ZipFile(filePath, 'r') as zf: for fn in zf.namelist(): right_fn = fn.encode('cp437').decode('utf-8') # 将文件名正确编码 right_fn = os.path.join(release_file_dir,right_fn) if right_fn[-1]=='/': os.makedirs(right_fn, mode=0o777) continue with open(right_fn, 'wb') as output_file: # 创建并打开新文件 with zf.open(fn, 'r') as origin_file: # 打开原文件 shutil.copyfileobj(origin_file, output_file) # 将原文件内容复制到新文件 |