首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python 3.x读取UTF-16文件似乎颠倒了字节顺序

Python 3.x读取UTF-16文件似乎颠倒了字节顺序
EN

Stack Overflow用户
提问于 2018-07-20 00:56:26
回答 3查看 1.2K关注 0票数 0

我正在尝试用Python读取Windows生成的UTF-16文件。据我所知,BOM是FEFF。这就是这个文件开始的地方。但是,当我将文件读入Python时,字节似乎被交换了。

代码语言:javascript
复制
(venv) [user]:~/consolidate$ head -c 16 temp.txt | od -x
0000000 feff 0022 0076 0065 0072 0073 0069 006f
0000020
(venv) [user]:~/consolidate$ python
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> with open('temp.txt', 'rb') as f:
...     str = f.readline()
...     print(str)
...
b'\xff\xfe"\x00v\x00e\x00r\x00s\x00i\x00o\x00n...

使用head时,第一个字符是feff 0022。使用Python,它看起来像是fffe2200。这里发生了什么事?

编辑:我的问题是关于字节顺序的。以下是几点:

  • ,我不想解码这个文件。这是一个10 on的文件,需要按一定的顺序拆分。
  • 它似乎只在第一行。
  • 写回文件将保留原始顺序。

第二行读取示例:

代码语言:javascript
复制
>>> with open('temp.txt', 'rb') as f:
...     str1 = f.readline()
...     str2 = f.readline()
...
>>> str2
b'\x00"\x00"\x00`\x00"\x00P\x
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-07-20 07:52:16

这里有三个不同的类似的事情。文件是一个字节序列,Python字节字符串b'\xff\xfe"\x00v\x00e\x00...'以字节在文件中的相同顺序显示内容:

代码语言:javascript
复制
FF FE 22 00 76 00 65 00

当您运行od -x时,它将字节对分组为16位数字。在Python系统上,2字节16位数字的标准字节排序是最低有效字节(“On byte")排在第一位,最高有效字节("256s byte")排在第二位(在x86,n=b[0]+256*b[1]中)。所以你得到了这个小尾数的解码:

代码语言:javascript
复制
FEFF  0022  0076  0065

同时,您希望将其解码为Unicode字符。只要没有高于U+FFFF的字符,UTF16Little-endian(UTF16LE)编码就会将相同的解码转换为Unicode字符:

代码语言:javascript
复制
U+FEFF U+0022 U+0076 U+0065
<BOM>     "      v      e

行的末尾发生了什么?让我们考虑字符串u'...",\n ...',并以相反的顺序完成此练习。

代码语言:javascript
复制
   "      ,     \n   <SPC>
U+0022 U+002C U+000A U+0020
22 00  2C 00  0A 00  20 00
b'"\x00,\x00\n\x00 \x00'

同时:如果您没有真正考虑字符编码,而是“将其拆分到换行符上”,会发生什么?你会看到[b'"\x00,\x00"', b'\n', b'\x00 \x00']的。这看起来像是第一部分是小端字节顺序(引号为null,逗号为null),但最后一部分是大端(空格)。但是后半部分实际上不是有效的UTF-16字符串:它包含奇数个字节,因为第一个字节实际上是换行符的后半部分。这就是当你调用readline时发生的事情。

您有几个选项来处理此问题。在另一个答案中提到的一种方法是open(filename, 'r', encoding='utf-16') (在文件模式中没有"b“)。然后,Python将执行正确的UTF-16解码(考虑到字节顺序标记),您将得到一个字符串。像str.readline这样的调用在这里也会做您所期望的事情。

你还说过你的目标只是拆分文件。如果您绝对确定该文件是UTF-16LE编码的(前两个字节肯定是FF FE),那么您可以将其作为字节字符串处理(使用问题代码中的模式'rb' ),并将其拆分到您想要的UTF-16编码的字节序列上

代码语言:javascript
复制
everything = f.read()
lines = everything.split(b'\x0A\x00')
for line in lines:
  parts = line.split(b'\x3A\x26')

如果您可以在一个块中读取整个文件,则更容易做到这一点;在Python中,读取10 GB的文件可能比较棘手。

票数 1
EN

Stack Overflow用户

发布于 2018-07-20 01:01:10

添加编码=‘utf-16’参数以打开

open('temp.txt', 'r', encoding='utf-16')

票数 0
EN

Stack Overflow用户

发布于 2018-07-20 01:10:15

您可以使用utf-16-le显式地将其解码为低端字节序,然后您就会收到预期的物料清单:

代码语言:javascript
复制
>>> b'\xff\xfe"\x00v\x00e\x00r\x00s\x00i\x00o\x00n\x00'.decode('utf-16-le')
'\ufeff"version'

如果您使用utf-16进行解码,它已经删除了物料清单:

代码语言:javascript
复制
>>> b'\xff\xfe"\x00v\x00e\x00r\x00s\x00i\x00o\x00n\x00'.decode('utf-16')
'"version'
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51428164

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档