Python - 有办法通过一行追踪文件对象的当前位置吗
我有一个测试文件 (不是 Python 脚本),里面包含了多个这样的序列:
测试文件 (不是 Python 脚本)
#Gibberish
#Gibberish
newSeq name-and-details
10 something
20 something
30 something
newSeq name-and-details
10 something
20 something
30 something
#Gibberish
#Gibberish
newSeq name-and-details
...and so forth
然后,我有一个 Python 脚本,它读取这个文件作为输入。对于每一个新的序列,都会创建一个新的 Python 列表来存储内容。
inputFile = open('testFile','r')
moreSeq = True
newLine = inputFile.readline()
while moreSeq:
while (not ('newSeq' in newLine)):
newLine = inputFile.readline()
newList = []
moreSeq = newList.listEntry(inputFile)
listDB.append(newList)
但是,当文件对象 inputFile 被传递给 listEntry 方法时,我希望它的位置能指向新的序列的开始,而不是后面的某个索引:
也就是说,我希望它指向 newSeq #1 这一行,而不是 10 something。
我该如何将文件对象的位置回溯到前一行,或者按固定行数回溯呢?我觉得使用 seek 方法在这种情况下不太管用。
4 个回答
解决这个问题的一个直接方法是使用 itertools.chain
,可以这样做:
moreSeq = newList.listEntry(itertools.chain([newline], inputFile))
这样一来,listEntry
方法就能看到一个符合你描述的可迭代对象。不过,我怀疑这并不能解决你在 listEntry
解析行并返回时遇到的问题。因为当那种情况发生时,你可能还想重新读取文件,因为 listEntry
可能会消耗掉其中一行 #Gibberish
。
我得说,你的代码看起来更像是 C 语言,而不是 Python。我觉得用 for line in f
这种风格的循环来读取行会更清晰。也许重新考虑一下你的方法,让它更符合 Python 语言的风格会更好。
我觉得可以用下面的方式来实现相同的效果:
lists = []
with open('testFile','r') as f:
for line in f:
if '#Gib' in line:
pass
elif 'newSeq' in line:
lists.append([])
else:
lists[-1].append(line)
这样做会返回一个包含所需行的列表的列表。你可以使用任何你想要的数据结构。如果newSeq的名字和细节是唯一的,那么我觉得用哈希表的列表会是一个更好的选择。
你可以使用 file.tell()
来查看文件中当前的字节位置,使用 file.seek()
可以把光标移动到你想要的新位置。通过这两个方法,再加上你刚刚读取的行的长度,应该就能轻松实现你想做的事情。
f = open('foo.txt')
f.readline() # output `bar`
f.tell() # output 3
f.seek(0) # go to the start of the file
这是一个常见的问题,通常可以通过重新读取这一行来解决,下面的代码就是这样做的:
class SmartReader(object):
def __init__(self, file):
self.file = file
self.lastline = None
def readline(self):
if self.lastline is not None:
ln = self.lastline
self.lastline = None
return ln
return self.file.readline()
def unreadline(self, line):
self.lastline = line
...
fd = SmartReader(open("file.txt"))
readMore = True
while readMore:
line = fd.readline()
if its_newSeq():
fd.unreadline(line)
close_the_previous_sequence()
else:
process_the_line()