5

从 Python 2.7 加载 unicode 文本的正确方法是:

content = open('filename').read().decode('encoding'):
for line in content.splitlines():
    process(line)

更新:不,不是。请参阅答案。)

但是,如果文件非常大,我可能想一次读取、解码和处理一行,这样整个文件就不会一次加载到内存中。就像是:

for line in open('filename'):
    process(line.decode('encoding'))        

循环在打开的文件句柄上的for迭代是一个一次读取一行的生成器。

但这不起作用,因为例如,如果文件是 utf32 编码的,那么文件中的字节(十六进制)看起来像:

hello\n = 68000000(h) 65000000(e) 6c000000(l) 6c000000(l) 6f000000(o) 0a000000(\n)

for并且由循环完成的分割成行分割字符的0a字节\n,导致(以十六进制表示):

lines[0] = 0x 68000000 65000000 6c000000 6c000000 6f000000 0a
lines[1] = 0x 000000

因此,部分\n字符留在第 1 行的末尾,其余三个字节在第 2 行结束(后面是实际在第 2 行中的任何文本。)decode可以理解的是,调用这些行中的任何一行都会导致UnicodeDecodeError.

UnicodeDecodeError: 'utf32' codec can't decode byte 0x0a in position 24: truncated data

因此,很明显,将 unicode 字节流拆分为0a字节并不是将其拆分为行的正确方法。相反,我应该在出现完整的四字节换行符 (0x0a000000) 时进行拆分。但是,我认为检测这些字符的正确方法是将字节流解码为 un​​icode 字符串并查找\n字符——而这种对完整流的解码正是我试图避免的操作。

这不能是一个不常见的要求。正确的处理方法是什么?

4

4 回答 4

7

试试类似的东西怎么样:

for line in codecs.open("filename", "rt", "utf32"):
    print line

我认为这应该有效。

codecs模块应该为您进行翻译。

于 2012-08-08T14:27:27.140 回答
4

尝试使用编解码器模块:

for line in codecs.open(filename, encoding='utf32'):
    do_something(line)
于 2012-08-08T14:26:45.063 回答
1

使用 codecs.open 而不是内置打开:

import codecs
for line in codecs.open('filename', encoding='encoding'):
    print repr(line)

http://docs.python.org/library/codecs.html#codecs.open

当然,我在完成我精心设计的 stackoverflow 问题后不久就发现了这一点。

于 2012-08-08T14:27:27.657 回答
1

codecs.open本身指出这io.open是一个更好的选择(注意就在链接目标上方)。它没有被弃用,只是因为它支持一些深奥的用途(字节->字节编解码器)。

io.open在 Python 2.6 及更高版本中可用,并提供与 Py3 的 built-in 相同的行为open,进行了更好的优化,并且不会codecs.open像行尾转换之类的东西那样行为不端。使用的唯一原因codecs.open是如果您需要支持 Python 2.5 及更早版本,否则io.open会更好。

import io

# Use with statement for guaranteed, predictable cleanup
with io.open('filename', encoding='utf-32') as f:
    for line in f:
        process(line)

顺便说一句,您可以使用 将任何已经打开的二进制类文件对象转换为基于文本的无缝解码对象io.TextIOWrapper因此如果其他人以二进制模式为您提供现有的类文件对象,您仍然可以通过以下方式隐式逐行解码:

def process_file(f):
    if 'b' in f.mode:  # Or some better test...
        f = io.TextIOWrapper(f, encoding='utf-32')
    for line in f:
        process(line)
于 2016-10-14T02:36:26.540 回答