Python3 str(),bytes和unicode

时间:2016-02-16 07:25:00

标签: python python-3.x unicode

我遇到了与我编写的这段代码有关的TYPES的问题。理想情况下,我不会介意编码类型,但有时你会被迫。

所以这都是围绕Windows上NTFS FS的目录遍历。文件名中的某些字符(unicode,似乎)无法写入文件或打印到标准的Windows终端(是的,我试过“chcp 65001”打印,这不起作用,但我需要写入无论如何都是标准的纯文本文件)

所以我做了以下事情。据我所知,Python3(我使用的是3.2.2)是unicode,因此str()对象(以及所有支持的lib)都是unicode,所以我这样做了:

absfilepath = os.path.join(root, file).encode()

认为utf-8字符串将被返回并且一切都很好,但是当我去写文件写入或stdout时,我得到了关于str()的隐式类型转换的错误。所以我做了以下事情:

hashmap[checksum] = str(absfilepath)

(稍后会转储hashmap)。

现在想想它是一个原生的unicode Python3字符串......但是当我将它转储到一个文件中时,使用它:

for key, val in m.items():
    f.write(key + "|" + val + "\n")

我仍然在文件中得到这个:

e77bceb64d179377731a94186e56281c|b'K:\Filename'

表示为字节数组。

那我在这里做错了什么?对不起'非传统'字符在这个目录树中,我宁愿他们不在那里,但他们在那里。如何将它们(转换它们?)存储为可以用普通纯文本(ASCII?)打印/写入的方式,为什么从我的hashmap返回一个字节数组,我清楚地存储了一个标准字符串?处理unicode对我来说是一次非常可怕的经历。

2 个答案:

答案 0 :(得分:3)

absfilepath = os.path.join(root, file).encode()

os.path.join()返回一个字符串,str.encode()将字符串转换为bytes对象,因此absfilepath包含一个bytes对象。

hashmap[checksum] = str(absfilepath)

当您在字节对象上调用str()时,字节对象解码,而是创建字符串表示:

>>> str(b'K:\Filename')
"b'K:\\\\Filename'"
>>> str(b'K:\Filename') == repr(b'K:\Filename')
True

因此,您的词典现在包含许多"b'some-bytes-string'"字符串。

“修复”很简单:只是不要编码从os.path.join得到的字符串。

如果在将字符串写入文件时出错,请考虑在文本模式下打开文件时指定显式编码:

with open('some_file', 'w', encoding='utf-8') as f:
    …

然后Python会自动正确地写字符串。

或者,为了完全安全,您还可以以二进制模式打开文件并编写编码的字符串:

with open('some_file', 'bw') as f:
    value = key + "|" + val + "\n"
    f.write(value.encode()) # write a bytes object

但只要您在 Python中,就不必担心字符串对象中的特殊字符。 Python可以处理它们;它只是通常失败的输出设备(例如打印到控制台)。

答案 1 :(得分:1)

您编码了您的unicode字符串:

absfilepath = os.path.join(root, file).encode()
#                                      ^^^^^^^^

这会产生一个字节串。要么不进行编码,要么再次将路径存储在hashmap 解码中:

hashmap[checksum] = absfilepath.decode()