【问题标题】:handling Unicode filenames in Python 3.4 on Windows在 Windows 上处理 Python 3.4 中的 Unicode 文件名
【发布时间】:2016-02-24 19:40:19
【问题描述】:

我正在尝试找到一种可靠的方法来使用 Python 扫描 Windows 上的文件,同时考虑文件名中可能存在各种 Unicode 代码点的可能性。我已经看到了几个针对这个问题提出的解决方案,但它们都不能解决我在扫描由现实世界的软件和用户创建的文件名时遇到的所有实际问题。

下面的代码示例试图解开和演示核心问题。它在一个子文件夹中创建了三个文件,其中包含我遇到的各种变体,然后尝试扫描该文件夹并显示每个文件名,后跟文件内容。它会在尝试读取第三个测试文件时崩溃,并带有 OSError [Errno 22] Invalid argument。

import os

# create files in .\temp that demonstrate various issues encountered in the wild
tempfolder = os.getcwd() + '\\temp'
if not os.path.exists(tempfolder):
    os.makedirs(tempfolder)
print('file contents', file=open('temp/simple.txt','w'))
print('file contents', file=open('temp/with a ® symbol.txt','w'))
print('file contents', file=open('temp/with these chars ΣΑΠΦΩ.txt','w'))

# goal is to scan the files in a manner that allows for printing
# the filename as well as opening/reading the file ...
for root,dirs,files in os.walk(tempfolder.encode('UTF-8')):
    for filename in files:
        fullname = os.path.join(tempfolder.encode('UTF-8'), filename)
        print(fullname)
        print(open(fullname,'r').read())

正如代码中所说,我只想能够显示文件名并打开/读取文件。关于文件名的显示,我不在乎是否针对特殊情况正确呈现了 Unicode 字符。我只想以唯一标识正在处理的文件的方式打印文件名,并且不会为这些不寻常的文件名类型抛出错误。

如果您注释掉最后一行代码,此处显示的方法将显示所有三个文件名而没有错误。但它不会打开名称中包含杂项 Unicode 的文件。

是否有一种方法可以在 Python 中可靠地显示/打开所有这三种文件名变体?我希望有,但我对 Unicode 微妙之处的有限掌握使我无法看到它.

【问题讨论】:

  • 你从哪里运行代码?
  • 来自命令提示符,或来自 VS Code,在这两种情况下都出现相同的错误。完成后,我需要从命令提示符运行它。
  • @DougMahugh,使用 pycharm 或 cygwin 之类的 ide 可以省去很多麻烦,代码应该可以完美地运行并显示输出,cmd shell 在编码方面很麻烦。 cygwin.com, jetbrains.com/pycharm/download
  • @DougMahugh,您可以花几个小时尝试获得一个允许您使用 cmd shell 的解决方案,但您会发现它永远无法正常工作,或者您只需花 15 分钟进行设置cygwin 或支持 utf-8 的 ide 就可以了。
  • @roeland,'mbcs' 通常是不正确的,因为控制台默认使用 OEM 代码页,而不是 ANSI 代码页。使用sys.stdout.encoding

标签: python windows python-3.x unicode


【解决方案1】:

以下工作正常,if 以声明的编码保存文件,if 使用支持所显示字符的 IDE 或终端编码。请注意,这不一定是 UTF-8。文件顶部的声明只是源文件的编码。

#coding:utf8
import os

# create files in .\temp that demonstrate various issues encountered in the wild
tempfolder = os.path.join(os.getcwd(),'temp')
if not os.path.exists(tempfolder):
    os.makedirs(tempfolder)
print('file contents', file=open('temp/simple.txt','w'))
print('file contents', file=open('temp/with a ® symbol.txt','w'))
print('file contents', file=open('temp/with these chars ΣΑΠΦΩ.txt','w'))

# goal is to scan the files in a manner that allows for printing
# the filename as well as opening/reading the file ...
for root,dirs,files in os.walk(tempfolder):
    for filename in files:
        fullname = os.path.join(tempfolder, filename)
        print(fullname)
        print(open(fullname,'r').read())

输出:

c:\\temp\simple.txt
file contents

c:\temp\with a ® symbol.txt
file contents

c:\temp\with these chars ΣΑΠΦΩ.txt
file contents

如果您使用的终端不支持对文件名中使用的字符进行编码,您将得到UnicodeEncodeError。变化:

print(fullname)

到:

print(ascii(fullname))

您会看到文件名被正确读取,但无法在终端编码中打印一个或多个符号:

'C:\\temp\\simple.txt'
file contents

'C:\\temp\\with a \xae symbol.txt'
file contents

'C:\\temp\\with these chars \u03a3\u0391\u03a0\u03a6\u03a9.txt'
file contents

【讨论】:

  • 很好的答案,但 utf-16 不是更适合 Windows 吗?
  • @tdelaney,声明的编码是源文件的编码。它与文件系统无关。更新了答案以使其更清楚。
  • @MarkTolonen - 我在考虑需要一个 utf-8 终端。我天真地假设 python3 标准输出编码将是 utf-16,因为控制台是本机宽字符。事实证明它仍然是基于代码页的。例如,OP 可以在常规 Windows 控制台上执行 `print(fullname.encode(sys.stdout.encoding, 'replace')) 。不在代码页中的字符将显示为“?”但否则它是无害的。并且不需要限制脚本的执行环境。
  • @tdelaney,控制台中的 Unicode(问题 1602)是一个未解决的老问题。 FileIO 基于字节和 POSIX readwrite。它不适合控制台。它需要一个调用ReadConsoleWWriteConsoleWRawIOBase 子类。 win-unicode-console 就是一个例子。它需要更好地与 REPL 和标记器集成,并提供 API(可能在 _winapi 中)和实现没有 ctypes 的 readline 模块所必需的钩子。
  • @DougMahugh,如果您使用UTF-8 with BOM 保存源代码,请改用#coding:utf-8-sig,或者直接忽略它,因为没有声明编码,UTF-8(有或没有 BOM)是默认值在 Python 3 上。我使用它是因为我使用 Python 编辑器自动以我声明的任何编码保存源代码,但如果省略,它默认(错误地)为“ANSI”(美国 Windows 上为Windows-1252)。
猜你喜欢
  • 2019-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-21
  • 2023-04-05
  • 1970-01-01
相关资源
最近更新 更多