在使用python处理文本的时候,经常会需要读取文件的内容。如果文件比较小,那么直接使用open文件对象打开文件,再通过read()方法最为方便,这种方法就是把文件内容读出来后放到内存变量。
read
f = open('/var/log/nginx/blog.nbqykj.cn.log','rb') #读取全部 log_data = f.read() f.close() # 按行读取
但是,当文件很大比如10GB,这种方法就会撑爆内存,爆出类似memoryError的错误。所以,要保险起见,可以反复调用read(size)
方法,每次最多读取size个字节的内容。
如果是处理连续文本内容,文件对象还支持readline()和readlines()两个方法。不同的是readline()没执行一次读取一行,readlines()会把所有内容都读出来。所以readlines方法不适用大文件。
readline
import time f = open('/var/log/nginx/blog.nbqykj.cn.log','rb') while True: print(f.readline()) time.sleep(1)
内存使用:占用不到4兆。
readlines
import time f = open('/var/log/nginx/blog.nbqykj.cn.log','rb') for line in f.readlines(): print(line) time.sleep(1)
内存使用:内存占用50多兆。
分块读取
那么另外一个比较好的办法是把大文件分块,这里用到python迭代器yield。
# 读取大文件 def read_in_chunks(file_path, chunk_size=1024*1024): """ Lazy function (generator) to read a file piece by piece. Default chunk size: 1M You can set your own chunk size """ file_object = open(file_path) while True: chunk_data = file_object.read(chunk_size) if not chunk_data: break yield chunk_data
默认一次读取1兆大小的内容。
with open
另外找到一个办法。可以用with语句打开和关闭文件,包括抛出一个内部块异常。for line in f文件对象f视为一个迭代器,会自动的采用缓冲IO和内存管理,所以你不必担心大文件。
with open(...) as f: for line in f: process(line) #
读取指定行内容
对于小文件,最简单是用readlines方法读取文件内容到列表,然后再使用列表和分片。
f = open('/var/log/nginx/blog.nbqykj.cn.log','rb') data = f.readlines() # 读取 第一行到第十行内容 print(data[0:10])
如果是大文件,可行的方法是先分块读取文件,然后再把指定行内容保存下来。不过这个办法有个小问题,被分块的那行内容取不全,而且效率不高。
例如:
# 读取文件多行间内容 def read_file_lines(file_path, line_start=1, line_end=-1): content_list = list() i = 1 for chunk in read_in_chunks(file_path, 1024*1024*10): for tmp in chunk.split('n'): if line_end != -1: if i >= line_start and i <= line_end: content_list.append(tmp) else: if i >= line_start: content_list.append(tmp) i += 1 return content_list
有更好的办法欢迎交流。
Python感觉比PHP还是难。
文章不错支持一下吧