按固定长度读取文件
1 def read_in_block(file_path): 2 BLOCK_SIZE = 100 3 with open(file_path, "rb") as f: 4 while True: 5 con = f.read(BLOCK_SIZE) # 每次读取固定长度到内存缓冲区 6 yield con 7 if con == b'': 8 break # 如果读取到文件末尾,则退出 9 10 fpath = "../file/1024.txt" 11 for block in read_in_block(fpath): 12 print(block)
这里给自己补充2个概念:
可迭代对象(Iterables)
创建一个列表list时,你可以逐个地读取里面的每一项元素,这个过程称之为迭代(iteration)
list = [1,2,3] for i in list: print(i)
迭代器(iterator)
迭代器代表一个数据流对象,不断重复调用迭代器的next()方法逐次的从返回数据流中的每一项,当没有更多数据可用时,next()方法会抛出异常StopIteration。此时迭代器对象已经枯竭了,之后调用next()方法都会抛出StopIteration。迭代器需要一个__iter__()方法用来返回迭代器本身,因此它也是一个可迭代的对象。
生成器(Generators)
生成器也是一个迭代器,但是你只可以迭代它们一次,不能重复迭代,因为它并没有把所有的值存储在内存中,而是实时地生成值:
Generators = (2*x for x in range(3)) for i in Generators: print(i)
从结果上看用()代替[]的效果是一样的,但是你不可能第二次执行for i in Generators:,因为生成器只能使用一次
Yield
yield是关键字,它类似于return,只是函数会返回一个生成器。
一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。
使用Yield的一个例子,从文件读取内容。
如果直接对文件 对象调用read()方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过yield,我们不在需要编写读取文件的迭代类,就可以轻松实现文件读取: