我有一个中等大小的文件(25MB,1000000行),我想读取除第三行之外的每一行。
第一个问题:将整个文件加载到内存中然后读取行(方法.read()
)还是一次加载并读取一行(方法{{ 1}})?
由于我不是经验丰富的编码人员,因此我尝试使用.readline()
模块中的islice
方法的第二种选择。
itertools
尽管循环通过单个生成器(import intertools
with open(input_file) as inp:
inp_atomtype = itertools.islice(inp, 0, 40, 3)
inp_atomdata = itertools.islice(inp, 1, 40, 3)
for atomtype, atomdata in itertools.zip_longest(inp_atomtype, inp_atomdata):
print(atomtype + atomdata)
或inp_atomtype
)可打印正确的数据,但同时循环通过两个生成器(如本代码所示)则会打印错误的数据。
第二个问题:如何使用生成器到达所需的行?
答案 0 :(得分:1)
您无需切片迭代器,一个简单的行计数器就足够了:
with open(input_file) as f:
current_line = 0
for line in f:
current_line += 1
if current_line % 3: # ignore every third line
print(line) # NOTE: print() will add an additional new line by default
关于将其变成生成器,只需yield
行而不是打印。
在速度方面,考虑到无论如何您都会读取行,I / O部分可能会花费相同的时间,但是您可能会受益于快速列表切片(总处理时间),而不是如果您有足够的工作内存来保留文件内容,并且如果可以预先加载整个文件而不是 streaming 是可以接受的。
答案 1 :(得分:0)
q2:这是我的发电机:
def yield_from_file(input_file):
with open(input_file) as file:
yield from file
def read_two_skip_one(gen):
while True:
try:
val1 = next(gen)
val2 = next(gen)
yield val1, val2
_ = next(gen)
except StopIteration:
break
if __name__ == '__main__':
for atomtype, atomdata in read_two_skip_one(yield_from_file('sample.txt')):
print(atomtype + atomdata)
sample.txt是使用bash shell生成的(只是数到100的行)
for i in {001..100}; do echo $i; done > sample.txt
关于q1:如果您多次读取文件,最好将其存储在内存中。否则,您可以逐行阅读它。
关于您遇到的结果错误的问题:
两个itertools.islice(inp, 0, 40, 3)
语句都将使用inp
作为生成器。两者都将调用next(inp)
,为您提供一个价值。
每次您在迭代器上调用next()
时,它都会更改其状态,这就是问题的出处。
答案 2 :(得分:0)
第一个问题:我很确定.readline()比.read()更快。另外,基于我的测试的最快方法是像
with open(file, 'r') as f:
for line in f:
...
第二个问题:我不太确定这件事。您可以考虑使用yield。
您可以参考以下代码段:
def myreadlines(f, newline):
buf = ""
while True:
while newline in buf:
pos = buf.index(newline)
yield buf[:pos]
buf = buf[pos + len(newline):]
chunk = f.read(4096)
if not chunk:
# the end of file
yield buf
break
buf += chunk
with open("input.txt") as f:
for line in myreadlines(f, "{|}"):
print (line)
答案 3 :(得分:0)
yield
对此非常适合。
此函数从可迭代对象中生成对,并跳过每三个项目:
def two_thirds(seq):
_iter = iter(seq)
while True:
yield (next(_iter), next(_iter))
next(_iter)
您将丢失一半对,这意味着two_thirds(range(2))
将立即停止迭代。
https://repl.it/repls/DullNecessaryCron
您还可以使用itertools doc中的石斑鱼食谱,而忽略每个生成的元组中的第三项:
for atomtype, atomdata, _ in grouper(lines, 3):
pass
答案 4 :(得分:0)
您可以使用生成器表达式:
with open(input_file, 'r') as f:
generator = (line for e, line in enumerate(f, start=1) if e % 3)
enumerate
将行号添加到每行,而if
子句将忽略被3整除的行号(默认编号从0开始,因此必须指定start=1
才能获得所需的行号)模式)。
请记住,您只能在文件仍打开的情况下使用生成器。