2014-08-27 80 views
2

我在Windows 7 64位上使用WinPython 2.7。Python 2.7:len()从换行符返回文件行的错误值

我想打开一个文件,逐行读取它的内容,当遇到特定的序列时,我想继续操作文件内容。

要保存当前位置,我将当前行的长度附加到行长度列表中。但是,len(line)返回的值太小了1.我怀疑这是由于Windows的换行符\r\n

考虑以下代码为例。

  • TESTFILE.TXT:

    Line1 
    Line2 
    Line3 
    
  • test.py

    fn = 'testfile.txt' 
    
    f = open(fn) 
    
    line_offsets = [] 
    for line in f: 
        line_offsets.append(len(line)) 
    
    f.seek(line_offsets[1]) 
    print '%r' % f.read() 
    
  • 输出:

    '\nLine2\nLine3' 
    
  • 预期输出:

    'Line2\nLine3' 
    

我试图通过指定的读法(用通用换行符)打开文件:f = open(fn, 'rU') 但这并没有这样的伎俩无论是。如果我以二进制模式打开文件,我可以使它工作,但这实际上是一个文本文件,而不是二进制文件,所以我想避免这种情况,我也想了解这里发生了什么。

回答

4

以二进制模式打开文件,并且'\r'不会从行中剥离。然后len将返回适当的字节数。

f = open(fn, 'rb') 

这将是,如果你的端口到Python 3尤为重要,因为非二进制文件将在您阅读和计数可能是方式关闭字节解码成Unicode字符。

+0

事实上,在Python 3中,你应该只能以相当有限的方式在文本文件中搜索。从教程中:'在文本文件(在模式字符串中没有ab的情况下打开的文件)中,只允许相对于文件的开头寻找(例外情况是以seek(0,2)寻找文件末尾),而只有有效的偏移值是从f.tell()返回的值,或者是零。任何其他偏移值都会产生未定义的行为。' – Blckknght 2014-08-27 17:22:40

+0

好吧,所以使用二进制模式似乎是我的方式。但为什么它不适用于'RU'?是不是通用的换行模式应该处理这种东西? – Vertho 2014-08-28 16:36:53

+0

@Vertho通用换行符在读取时会明确地转换为'\ n',所以如果文件包含'\ r \ n'作为两个字符,那么您的字符串将只包含'\ n' - 它根本无助于您的问题。即使在文本模式下打开文件,seek也始终以二进制模式工作。 – 2014-08-28 16:51:24

0

您可以使用splitlines()从文件中删除这些行。它根据documentation对各种换行符具有容差。

0

为了获得您想要的行为,您可以在读取每行之前明确地调用f.tell(),然后使用f.readline()来读取该行。由于Windows issue with tell(),您可能还必须以二进制模式工作,并自行处理任何行结束问题。使用该文件作为迭代器将无法正常工作,因为它会被缓冲,并且可能会使文件指针超出您在文件中读取的行。

>>> with open('testfile.txt', 'rb') as f: 
...  while True: 
...   here = f.tell() 
...   line = f.readline() 
...   if not line: 
...    break 
...   print('%02d\t%r' % (here, line)) 
... 
00 'Line1\n' 
06 'Line2\n' 
12 'Line3\n' 
+0

有没有保证'f.readline'不会缓冲? - 我可以很容易地看到这在不同的python实现/版本上打破... – mgilson 2014-08-27 18:06:46

+0

不,但它适用于CPython 2/3和PyPy。我希望其他实现可以在这里遵守事实上的标准行为。 – 2014-08-27 20:22:24