在Python 2.5中,我正在使用文件指针读取结构化文本数据文件(大小约30 MB):
fp = open('myfile.txt', 'r')
line = fp.readline()
# ... many other fp.readline() processing steps, which
# are used in different contexts to read the structures
然而,在解析文件时,我点击了一些有趣的东西,我想报告行号,所以我可以在文本编辑器中调查该文件。我可以使用fp.tell()
告诉我字节偏移的位置(例如16548974L
),但没有“fp.tell_line_number()”来帮助我将其转换为行号。
是否有内置的Python或扩展程序可以轻松跟踪并“告诉”文本文件指针所在的行号?
注意:我not asking使用line_number += 1
样式计数器,因为我在不同的上下文中调用fp.readline()
,这种方法需要更多的调试,而不是插入计数器的值在代码的右角。
答案 0 :(得分:14)
此问题的典型解决方案是定义一个新类,它包装file
的现有实例,自动计算数字。像这样的东西(就在我的头顶,我没有测试过这个):
class FileLineWrapper(object):
def __init__(self, f):
self.f = f
self.line = 0
def close(self):
return self.f.close()
def readline(self):
self.line += 1
return self.f.readline()
# to allow using in 'with' statements
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
像这样使用:
f = FileLineWrapper(open("myfile.txt", "r"))
f.readline()
print(f.line)
看起来标准模块fileinput
做了很多相同的事情(以及其他一些事情);如果你愿意,你可以使用它。
答案 1 :(得分:11)
您可能会发现fileinput
模块很有用。它提供了一个用于迭代任意数量文件的通用接口。文档中的一些相关要点:
fileinput.lineno()
返回刚刚读取的行的累计行号。在读取第一行之前,返回0.读取完最后一个文件的最后一行后,返回该行的行号。
fileinput.filelineno()
返回当前文件中的行号。在读取第一行之前,返回0.读取完最后一个文件的最后一行后,返回该行中该行的行号。
答案 2 :(得分:9)
以下代码将在遍历文件('testfile')时打印行号(指针当前所在的位置)
file=open("testfile", "r")
for line_no, line in enumerate(file):
print line_no # The content of the line is in variable 'line'
file.close()
<强>输出:强>
1
2
3
...
答案 3 :(得分:1)
我不这么认为,不是按照你想要的方式(如open
返回的Python文件句柄的标准内置功能)。
如果您在阅读行或使用包装类时无法手动跟踪行号(顺便提一下GregH和senderle的优秀建议),那么我认为您只需使用fp.tell()
数字,然后回到文件的开头,直到你到达那里。
这不是太糟糕的一个选项,因为我假设错误条件不太可能比游泳的所有工作。如果一切正常,那就没有影响了。
如果出现错误,则需要额外重新扫描文件。如果文件 big,可能会影响您的感知效果 - 如果这是一个问题,您应该考虑到这一点。
答案 4 :(得分:0)
一种方法可能是迭代线并保持已经看到的行数的明确计数:
>>> f=open('text.txt','r')
>>> from itertools import izip
>>> from itertools import count
>>> f=open('test.java','r')
>>> for line_no,line in izip(count(),f):
... print line_no,line
答案 5 :(得分:0)
以下代码创建一个函数 Which_Line_for_Position(pos),为 pos 位置提供行数,也就是说行号,其中的字符位于文件中 pos 的位置。
此函数可以作为参数使用任何位置,与文件指针的当前位置的值无关,也可以在调用函数之前从该指针的移动历史记录中使用。
因此,使用此函数,不仅限于在线上不间断迭代期间确定当前行的数量,就像Greg Hewgill的解决方案一样。
with open(filepath,'rb') as f:
GIVE_NO_FOR_END = {}
end = 0
for i,line in enumerate(f):
end += len(line)
GIVE_NO_FOR_END[end] = i
if line[-1]=='\n':
GIVE_NO_FOR_END[end+1] = i+1
end_positions = GIVE_NO_FOR_END.keys()
end_positions.sort()
def Which_Line_for_Position(pos,
dic = GIVE_NO_FOR_END,
keys = end_positions,
kmax = end_positions[-1]):
return dic[(k for k in keys if pos < k).next()] if pos<kmax else None
可以在 fileinput 模块的帮助下编写相同的解决方案:
import fileinput
GIVE_NO_FOR_END = {}
end = 0
for line in fileinput.input(filepath,'rb'):
end += len(line)
GIVE_NO_FOR_END[end] = fileinput.filelineno()
if line[-1]=='\n':
GIVE_NO_FOR_END[end+1] = fileinput.filelineno()+1
fileinput.close()
end_positions = GIVE_NO_FOR_END.keys()
end_positions.sort()
def Which_Line_for_Position(pos,
dic = GIVE_NO_FOR_END,
keys = end_positions,
kmax = end_positions[-1]):
return dic[(k for k in keys if pos < k).next()] if pos<kmax else None
但是这个解决方案有一些不便之处:
为例:
text = '''Harold Acton (1904–1994)
Gilbert Adair (born 1944)
Helen Adam (1909–1993)
Arthur Henry Adams (1872–1936)
Robert Adamson (1852–1902)
Fleur Adcock (born 1934)
Joseph Addison (1672–1719)
Mark Akenside (1721–1770)
James Alexander Allan (1889–1956)
Leslie Holdsworthy Allen (1879–1964)
William Allingham (1824/28-1889)
Kingsley Amis (1922–1995)
Ethel Anderson (1883–1958)
Bruce Andrews (born 1948)
Maya Angelou (born 1928)
Rae Armantrout (born 1947)
Simon Armitage (born 1963)
Matthew Arnold (1822–1888)
John Ashbery (born 1927)
Thomas Ashe (1836–1889)
Thea Astley (1925–2004)
Edwin Atherstone (1788–1872)'''
#with open('alao.txt','rb') as f:
f = text.splitlines(True)
# argument True in splitlines() makes the newlines kept
GIVE_NO_FOR_END = {}
end = 0
for i,line in enumerate(f):
end += len(line)
GIVE_NO_FOR_END[end] = i
if line[-1]=='\n':
GIVE_NO_FOR_END[end+1] = i+1
end_positions = GIVE_NO_FOR_END.keys()
end_positions.sort()
print '\n'.join('line %-3s ending at position %s' % (str(GIVE_NO_FOR_END[end]),str(end))
for end in end_positions)
def Which_Line_for_Position(pos,
dic = GIVE_NO_FOR_END,
keys = end_positions,
kmax = end_positions[-1]):
return dic[(k for k in keys if pos < k).next()] if pos<kmax else None
print
for x in (2,450,320,104,105,599,600):
print 'pos=%-6s line %s' % (x,Which_Line_for_Position(x))
结果
line 0 ending at position 25
line 1 ending at position 51
line 2 ending at position 74
line 3 ending at position 105
line 4 ending at position 132
line 5 ending at position 157
line 6 ending at position 184
line 7 ending at position 210
line 8 ending at position 244
line 9 ending at position 281
line 10 ending at position 314
line 11 ending at position 340
line 12 ending at position 367
line 13 ending at position 393
line 14 ending at position 418
line 15 ending at position 445
line 16 ending at position 472
line 17 ending at position 499
line 18 ending at position 524
line 19 ending at position 548
line 20 ending at position 572
line 21 ending at position 600
pos=2 line 0
pos=450 line 16
pos=320 line 11
pos=104 line 3
pos=105 line 4
pos=599 line 21
pos=600 line None
然后,使用函数 Which_Line_for_Position(),很容易获得当前行的编号:只需将 f.tell()作为参数传递给函数< / p>
但是警告:当使用 f.tell()并在文件中移动文件指针时,绝对有必要以二进制模式打开文件:'rb'或'rb +'或'ab'或....
答案 6 :(得分:0)
最近遇到类似的问题并提出了这个基于类的解决方案。
class TextFileProcessor(object):
def __init__(self, path_to_file):
self.print_line_mod_number = 0
self.__path_to_file = path_to_file
self.__line_number = 0
def __printLineNumberMod(self):
if self.print_line_mod_number != 0:
if self.__line_number % self.print_line_mod_number == 0:
print(self.__line_number)
def processFile(self):
with open(self.__path_to_file, 'r', encoding='utf-8') as text_file:
for self.__line_number, line in enumerate(text_file, start=1):
self.__printLineNumberMod()
# do some stuff with line here.
将print_line_mod_number
属性设置为您要记录的节奏,然后拨打processFile
。
例如......如果您想要每100行反馈一次,就会看起来像这样。
tfp = TextFileProcessor('C:\\myfile.txt')
tfp.print_line_mod_number = 100
tfp.processFile()
控制台输出将是
100
200
300
400
etc...
答案 7 :(得分:0)
使用with
上下文管理器打开文件,并在for
循环中枚举行。
with open('file_name.ext', 'r') as f:
[(line_num, line) for line_num, line in enumerate(f)]
答案 8 :(得分:-1)
关于solution by @eyquem,我建议将mode='r'
与fileinput模块和fileinput.lineno()
选项一起使用,它对我有用。
以下是我在代码中实现这些选项的方法。
table=fileinput.input('largefile.txt',mode="r")
if fileinput.lineno() >= stop : # you can disregard the IF condition but I am posting to illustrate the approach from my code.
temp_out.close()