我有一个以 centos7 作为基础镜像的 Docker 容器,并且
python --version
= Python 2.7.5
和 python3 --version
= Python 3.6.8
。
我的 ENTRYPOINT 是一个短的
run.sh
文件。
#!/bin/bash
locale >> locale.txt
python3 /home/scripts/script.py >> output.txt
while :
do
sleep 10000
done
script.py
是:
#!/bin/python
path_to_file = '/home/file.json'
print('starting')
try:
with open(path_to_file, "r") as file:
data = file.read()
print(data)
except Exception as e: print(e)
print('ending')
最后,
/home/file.json
仅包含:
"°"
启动容器并使用
docker exec -it container-name bash
输入后,我检查 output.txt
,其内容为:
starting
'ascii' codec can't decode byte 0xc2 in position 1: ordinal not in range(128)
ending
将
python3
中的 python
更改为 run.sh
并重做该过程会导致 output.txt
具有:
starting
"°"
ending
在这两种情况下,locale.txt 都有:
LANG=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=
但是,在 Docker 容器的 bash 会话中在我的终端中运行
locale
会给出:
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
在 bash 会话中运行
python3 script.py
给我:
starting
"°"
ending
我在文档中发现,如果系统没有配置字符集,Python 2 会从系统配置中读取并使用 ASCII。当
encoding
参数未提供给 open
函数时,Python 3 的行为方式似乎相同。我一定是误解了文档?
Python 2 和 Python 3 之间的区别是什么导致在 Docker 容器的 ENTRYPOINT 脚本中运行时 Python 2 成功而 Python 3 失败?
Python 2 根本不尝试处理编码。它天真地逐字节读取。
相比之下,Python 3 区分以二进制模式打开的文件(逐字节读取,并返回bytes
对象)和文本模式(尝试使用编码,如果文件包含以下序列则失败)在该编码中无效,如果成功则返回
str
)。您尚未识别文件的编码;如果它是有效的 UTF-8 文件(这是我通常推荐的),请使用
encoding="utf-8"
。在 Windows 上,您可能需要不同的编码;但当然,您需要了解字符编码,并指定正确的编码。要强制Python 3使用特定编码,而不更改源文件,可以将环境变量
PYTHONIOENCODING
设置为合适的值;例如
export PYTHONIOENCODING="utf-8"
另请参阅 https://nedbatchelder.com/text/unipain.html 和 Joel Spolsky 的 每个软件开发人员绝对必须了解 Unicode 和字符集(没有例外!)
如果您需要帮助识别文本文件的编码,请尝试https://tripleee.github.io/8bit/(全面披露:我是此页面的作者)配备十六进制转储或 Python 3 的 repr
文件中的字节数(...尽管这对于 UTF-8 没有帮助,所以也许可以先尝试一下)。