为了简化我的问题,我创建了一个可运行的演示,该示例应根据有关处理文件名的python unicode文档进行工作。输出如下:

$ ./test_unicode.py /tmp/gsynctest/Greg.*
p = '/tmp/gsynctest/Greg. Descripci\xf3n v\xeddeos'
up = u'/tmp/gsynctest/Greg. Descripci\xf3n v\xeddeos'
up.utf8 = /tmp/gsynctest/Greg. Descripción vídeos
Command line file exists = True
Unicode file exists = False
UTF-8 file exists = False


如您所见,按出现顺序,p是argv和glob提供的文件名。尽管我的终端具有LANG =“ en_GB.UTF-8”,但它仍具有“ latin-1”编码。如果我在设置严格的Unicode错误的情况下对其进行解码,则会得到up所示的字符串。如果再用utf8进行编码,则会得到代表真实文件名的内容。

但是,根据unicode文档,应使用sys.getfilesystemencoding()对访问它的unicode文件名进行编码。但是,这不起作用。三个exists检查显示哪一个有效,并且似乎是latin-1(ISO-8859-1)编码。

我不知道为什么我看到的内容不反映文档。

这是测试程序代码:

#!/usr/bin/env python

import sys, os

paths = sys.argv[1:]

fsenc = sys.getfilesystemencoding()

for p in paths:
    print "p = %s" % repr(p)

    if not isinstance(p, unicode):
        up = unicode(p, encoding = "latin-1", errors = "strict")

    print "up = %s" % repr(up)
    print "up.utf8 = %s" % up.encode("utf8")

    print "Command line file exists = %s" % os.path.exists(p)
    print "Unicode file exists = %s" % os.path.exists(up)
    print "%s file exists = %s" % (fsenc, os.path.exists(up.encode(fsenc)))


。 。 。

原始问题:

如果尝试以原始格式解码以下文件名表示形式,则会收到“无效的继续字节”错误:Greg. Descripci\xf3n v\xeddeos\n

for p in paths:
    p = p.decode(sys.getfilesystemencoding())


这是提交此错误的用户提交的真实文件名。我对unicode / UTF-8编码的理解不是很好,但是据我所知,它不是合法的UTF-8,因为它需要某种终止符。我并不在乎文件名在打印时的样子,只需要在磁盘上访问即可。处理此类文件的常规方式是什么?我的大多数问题都来自尝试打印文件:

debug(u"Filename: %s" % unicode(path))


更新:请尝试,再努力,再努力仍然有好处吗?

for e in (sys.getfilesystemencoding(), "UTF-8", "Latin-1"):
    try:
        p_dec = p.decode("Latin-1")
        p = p_dec.encode(sys.getfilesystemencoding())
    except UnicodeDecodeError:
        pass


对于文件系统编码相同的编码,显然不是那么理想,因为它将以相同的编码进行解码和编码。但是至少我可以保证不会有任何后续调用对文件名进行解码的异常。我看到的唯一问题是,不正确的编码可能会解码文件名而不会出错,从而产生完全错误的编码文件名。

无论哪种方式,我都需要跟踪两个文件名吗?磁盘上可访问的原始文件名和可打印文件名?还是文件系统编码的文件名既可打印又可访问?

更新2:我的问题的答案是“否”。我实现了自己的编解码器,以循环编码类型并在文件系统编码中重新编码。现在可以打印该表示形式:Greg. Descripción vídeos,但是不再可访问该文件。因此,我认为保留文件系统访问和可打印性的最简单方法是将文件名包装在具有用于打印和IO的实现的类中。除非有人有其他建议?

最佳答案

首先,仅编写unicode(path)几乎总是一个坏主意。如果需要将字符串转换为Unicode,则需要知道它所在的字符集。

假设p代表文件系统的路径(例如,您是从os.listdir获取的),那么您希望使用文件系统的编码对其进行解码,而不仅仅是Python认为是不错的默认值。*因此,就是您上面已经做过的:

p = p.decode(sys.getfilesystemencoding())


如果path代表其他内容(例如,您是从用户输入中得到的),则情况有所不同。

或者,如果path是您已经在上面计算出的这些p值之一,则它已经是unicode,因此尝试再次对其进行解码将将其重新编码为默认编码,然后对其进行重新解码,这是一件愚蠢的事。

但是,如果不知道字符串从何而来,您(和我们)就无法知道它所在的字符集,因此就无法解码。



*在某些系统上,您会很幸运。例如,在Mac上使用Python 3.x,默认编码和文件系统编码都将始终为UTF-8。但是在较旧的Linux机器上使用Python 2.x时,默认编码可能是UTF-8,而文件系统是Latin-1…这似乎正是您在这里得到的。

关于python - 解码文件名问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19124233/

10-10 14:05
查看更多