从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
因此,显然,在0a
字节上拆分unicode字节流不是将其拆分为行的正确方法。相反,我应该分裂出现完整的四字节换行符(0x0a000000)。但是,我认为检测这些字符的正确方法是将字节流解码为unicode字符串并查找\n
个字符 - 这个完整流的解码正是我试图避免的操作。 / p>
这不是一个不常见的要求。处理它的正确方法是什么?
答案 0 :(得分:7)
尝试类似的事情:
for line in codecs.open("filename", "rt", "utf32"):
print line
我认为这应该有用。
codecs
模块应该为您进行翻译。
答案 1 :(得分:4)
尝试使用编解码器模块:
for line in codecs.open(filename, encoding='utf32'):
do_something(line)
答案 2 :(得分:1)
使用codecs.open而不是builtin open:
import codecs
for line in codecs.open('filename', encoding='encoding'):
print repr(line)
http://docs.python.org/library/codecs.html#codecs.open
当然,我在完成精心设计的stackoverflow问题后发现了这一点。
答案 3 :(得分:1)
codecs.open
itself notes that io.open
is a better option(注意就在链接目标之上)。它不被弃用,只是因为它支持一些深奥的用法(字节 - >字节编解码器)。
io.open
is available in Python 2.6 and higher,并提供与Py3的内置open
相同的行为,更好地优化,并且在codecs.open
时不会像codecs.open
那样行为不端像行结束转换的东西。使用io.open
的唯一原因是,如果您需要支持Python 2.5及更早版本,否则import io
# Use with statement for guaranteed, predictable cleanup
with io.open('filename', encoding='utf-32') as f:
for line in f:
process(line)
严格来说更好。
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)
顺便提一下,您可以将任何已打开的二进制文件类对象转换为基于无缝解码文本的对象using io.TextIOWrapper
,因此如果其他人以二进制文件为您提供现有的类文件对象模式,您仍然可以使用以下方式进行逐行解码:
SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd" );
Calendar cal = Calendar.getInstance();
cal.setTime( dateFormat.parse( inputString ) );
cal.add( Calendar.DATE, 7 );