如果我将两种编码字符串(例如utf-8和utf-16)放在一个文件中怎么办?

nre*_*rek 3 python unicode utf-8 utf-16

在Python中,例如:

f = open('test','w')
f.write('this is a test\n'.encode('utf-16'))
f.write('another test\n'.encode('utf-8'))
f.close()
Run Code Online (Sandbox Code Playgroud)

当我重新打开它时,该文件变得混乱:

f = open("test")
print f.readline().decode('utf-16')  # it leads to UnicodeDecodeError
print f.readline().decode('utf-8')   # it works fine
Run Code Online (Sandbox Code Playgroud)

但是,如果我将文本编码为一种样式(仅限utf-16),它可以回读确定.所以我猜测在同一个文件中混合两种类型的编码是错误的并且无法解码回来,即使我知道每个特定字符串的编码规则?欢迎任何建议,谢谢!

Mar*_*ers 5

这通常是一个坏主意,但在你的情况下它不起作用,因为你也编码换行符.

在UTF-16中,每个字符都被编码为两个字节,包括您编写的换行符.因为你逐行读取你的文件,python会给你从文件到下一个换行字节的所有数据,但在UTF-16中,这可能意味着两个字节中的一个仍然包含在返回的数据中,导致不完整UTF-16字节流.

要理解这一点,您需要更详细地了解UTF-16编码.当将16位数据写为8位的2字节时,计算机需要首先决定将哪个字节写入文件.这一决定可以去两种方式,被称为字节顺序 ; 像Gulliver的Lilliputs,计算机系统更喜欢Big或Little端序.

因此,UTF-16数据流以两种顺序之一写入,并且首先写入字节顺序标记或"BOM"以标记选择哪一个.

因此,您的换行符编码为'\n\x00''\x00\n',并且在读取时,null byte(\x00)是您解码的UTF-16数据的一部分,或UTF-8数据(忽略它的位置).因此,如果您将UTF-16编码为大端,那么事情就会起作用(但是您有一个迷失的空字节),但是如果您编码为小端,则事情会中断.

基本上,编码数据应严格地作为二进制数据处理,您应该使用不同的方法来描绘不同的编码文本,或者您应该只使用编码,其中新行严格编码为换行符.

我使用长度前缀,首先读取,然后从文件中读取每个编码数据的字节数.

>>> import struct
>>> f = open('test', 'wb')
>>> entry1 = 'this is a test\n'.encode('utf-16')
>>> struct.pack('!h', len(entry1)))
>>> f.write(entry1)
>>> entry2 = 'another test\n'.encode('utf-8')
>>> f.write(struct.pack('!h', len(entry2)))
>>> f.write(entry2)
>>> f.close()
Run Code Online (Sandbox Code Playgroud)

我用这个struct模块写了固定长度的数据.请注意,我也将文件写为二进制文件.

读:

>>> f = open('test', 'rb')
>>> fieldsize = struct.calcsize('!h')
>>> length = struct.unpack('!h', f.read(fieldsize))[0]
>>> print f.read(length).decode('utf-16')
this is a test

>>> length = struct.unpack('!h', f.read(fieldsize))[0]
>>> print f.read(length).decode('utf-8')
another test

>>>
Run Code Online (Sandbox Code Playgroud)

文件再次以二进制模式打开.

在实际应用程序中,您可能还必须在每个条目中包含编码信息.