3

我有一个巨大的压缩文本文件,我需要逐行阅读。我选择以下内容:

for i, line in enumerate(codecs.getreader('utf-8')(gzip.open('file.gz'))):
  print i, line

在文件后期的某个时间点,python 输出与文件不同。这是因为由于 python 认为是换行符的奇怪特殊字符而导致行被中断。当我在“vim”中打开文件时,它们是正确的,但可疑字符的格式很奇怪。我能做些什么来解决这个问题吗?

我尝试过其他编解码器,包括 utf-16、latin-1。我也试过没有编解码器。

我用“od”查看了文件。果然,有 \n 字符它们不应该在。但是,“错误”的前面有一个奇怪的字符。我认为这里有一些编码,其中一些字符是 2 字节,但如果没有正确查看,尾随字节是 \n。

根据'od -h file',违规字符是'1d1c'。

如果我更换:

gzip.open('file.gz')

和:

os.popen('zcat file.gz')

它工作正常(实际上,速度更快)。但是,我想知道我哪里出错了。

4

2 回答 2

5

不使用编解码器重试。以下是使用编解码器时重现您的问题,而没有它则没有问题:

import gzip 
import os 
import codecs 

data = gzip.open("file.gz", "wb") 
data.write('foo\x1d\x1cbar\nbaz') 
data.close() 

print list(codecs.getreader('utf-8')(gzip.open('file.gz'))) 
print list(os.popen('zcat file.gz')) 
print list(gzip.open('file.gz')) 

输出:

[u'foo\x1d', u'\x1c', u'bar\n', u'baz']
['foo\x1d\x1cbar\n', 'baz']
['foo\x1d\x1cbar\n', 'baz']
于 2010-05-02T04:20:28.013 回答
1

我问(在评论中)“”“向我们展示 print repr(weird_special_characters) 的输出。当你在 vim 中打开文件时,什么是正确的?请比“格式化奇怪”更精确。”“”但什么都没有:- (

你在看什么文件odfile.gz?? 如果您可以在其中看到任何可识别的内容,则它不是 gzip 文件!您没有看到换行符,您看到的是包含 0x0A 的二进制字节。

如果原始文件是 utf-8 编码的,那么用其他编解码器尝试它的意义何在?

“使用 zcat 可以正常工作”是否意味着您在没有 utf8 解码步骤的情况下获得了可识别的数据?

我建议您简化代码,并一次执行一步……例如,请参阅此问题的接受答案。再试一次,请显示您运行的确切代码,并在描述结果时使用 repr()。

更新看起来 DS 已经猜到了您试图解释的有关 \x1c 和 \x1d 的内容。

以下是关于为什么会发生这种情况的一些说明:

在 ASCII 中,换行时只考虑 \r 和 \n:

>>> import pprint
>>> text = ''.join('A' + chr(i) for i in range(32)) + 'BBB'
>>> print repr(text)
'A\x00A\x01A\x02A\x03A\x04A\x05A\x06A\x07A\x08A\tA\nA\x0bA\x0cA\rA\x0eA\x0fA\x10
A\x11A\x12A\x13A\x14A\x15A\x16A\x17A\x18A\x19A\x1aA\x1bA\x1cA\x1dA\x1eA\x1fBBB'
>>> pprint.pprint(text.splitlines(True))
['A\x00A\x01A\x02A\x03A\x04A\x05A\x06A\x07A\x08A\tA\n', # line break
 'A\x0bA\x0cA\r', # line break
 'A\x0eA\x0fA\x10A\x11A\x12A\x13A\x14A\x15A\x16A\x17A\x18A\x19A\x1aA\x1bA\x1cA\x
1dA\x1eA\x1fBBB']
>>>

但是在 Unicode 中,字符 \x1D(文件分隔符)、\x1E(组分隔符)和 \x1E(记录分隔符)也可以作为行尾:

>>> text = u''.join('A' + unichr(i) for i in range(32)) + u'BBB'
>>> print repr(text)
u'A\x00A\x01A\x02A\x03A\x04A\x05A\x06A\x07A\x08A\tA\nA\x0bA\x0cA\rA\x0eA\x0fA\x10A\x11A\x12A\x13A\x14A\x15A\x16A\x17A\x18A\x19A\x1aA\x1bA\x1cA\x1dA\x1eA\x1fBBB'
>>> pprint.pprint(text.splitlines(True))
[u'A\x00A\x01A\x02A\x03A\x04A\x05A\x06A\x07A\x08A\tA\n', # line break
 u'A\x0bA\x0cA\r', # line break
 u'A\x0eA\x0fA\x10A\x11A\x12A\x13A\x14A\x15A\x16A\x17A\x18A\x19A\x1aA\x1bA\x1c', # line break
 u'A\x1d', # line break
 u'A\x1e', # line break
 u'A\x1fBBB']
>>>

无论您使用什么编解码器,这都会发生。您仍然需要确定需要使用什么(如果有)编解码器。您还需要确定原始文件是否真的是文本文件而不是二进制文件。如果是文本文件,需要考虑文件中\x1c和\x1d的含义。

于 2010-04-30T02:28:17.750 回答