在 Windows 上将 python 输出重定向到文件会导致 UnicodeEncodeError

san*_*der 7 python windows encoding

我正在尝试将 python 脚本的输出重定向到文件。当输出包含非 ascii 字符时,它可以在 macOS 和 Linux 上运行,但不能在 Windows 上运行。

\n\n

我已经将问题推导为一个简单的测试。以下是 Windows 命令提示符窗口中显示的内容。测试只是一次打印调用。

\n\n
Microsoft Windows [Version 10.0.17134.472]\n(c) 2018 Microsoft Corporation. All rights reserved.\n\nD:\\>set PY\nPYTHONIOENCODING=utf-8\n\nD:\\>type pipetest.py\nprint(\'\\u0422\\u0435\\u0441\\u0442\')\n\nD:\\>python pipetest.py\n\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82\n\nD:\\>python pipetest.py > test.txt\n\nD:\\>type test.txt\n\xe2\x95\xa8\xc3\xb3\xe2\x95\xa8\xe2\x95\xa1\xe2\x95\xa4\xc3\xbc\xe2\x95\xa4\xc3\xa9\n\nD:\\>type test.txt | iconv -f utf-8 -t utf-8\n\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82\n\nD:\\>set PYTHONIOENCODING=\n\nD:\\>python pipetest.py\n\xd0\xa2\xd0\xb5\xd1\x81\xd1\x82\n\nD:\\>python pipetest.py > test.txt\nTraceback (most recent call last):\n  File "pipetest.py", line 1, in <module>\n    print(\'\\u0422\\u0435\\u0441\\u0442\')\n  File "C:\\Python\\Python37\\lib\\encodings\\cp1252.py", line 19, in encode\n    return codecs.charmap_encode(input,self.errors,encoding_table)[0]\nUnicodeEncodeError: \'charmap\' codec can\'t encode characters in position 0-3: character maps to <undefined>\n\nD:\\>python -V\nPython 3.7.2\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如人们所看到的,设置 PYTHONIOENCODING 环境变量有帮助,但我不明白为什么需要设置它。当输出是终端时,它可以工作,但如果输出是文件,它会失败。当 stdout 不是控制台时,为什么使用 cp1252?

\n\n

也许这是一个错误,可以在 Windows 版本的 python 中修复?

\n

小智 6

基于Python文档,Windows版本在控制台设备(utr-8)和非字符设备(例如磁盘文件和管道(系统区域设置))上使用不同的字符编码。PYTHONIOENCODING 可用于覆盖它。

https://docs.python.org/3/library/sys.html#sys.stdout

另一种方法是直接在程序中更改编码,我尝试过,效果很好。

sys.stdout.reconfigure(encoding='utf-8')
Run Code Online (Sandbox Code Playgroud)

https://docs.python.org/3/library/io.html#io.TextIOWrapper.reconfigure


san*_*der 0

Python 需要将二进制数据写入stdout(而不是字符串),因此需要编码参数。

每个平台的编码(用于将字符串转换为字节)的确定方式不同:

  • 在 Linux 和 macOS 上,它来自当前区域设置;
  • 在 Windows 上,使用的是“非 Unicode 程序的当前语言”(命令行窗口中设置的代码页无关)。

(感谢@Eric Leung 提供精确链接)

后续问题是为什么 Windows 上的 Python 对非 Unicode 程序使用当前系统区域设置,而不是通过chcp命令设置的区域设置,但我将把它留给其他人。

还需要提到的是,Windows 10 的“区域设置”中有一个标题为“Beta:使用 Unicode UTF-8...”的复选框(要打开 - Win+R,键入intl.cpl)。通过选中该复选框,上面的示例可以正常运行,不会出现错误。但这个复选框默认是关闭的,并且在系统设置中非常深入。