我希望遍历整个文件的每一行。一种方法是读取整个文件,将其保存到一个列表中,然后遍历感兴趣的行。这种方法使用大量内存,所以我正在寻找一种替代方法。
到目前为止我的代码:
for each_line in fileinput.input(input_file):
do_something(each_line)
for each_line_again in fileinput.input(input_file):
do_something(each_line_again)
执行这段代码会给出一个错误消息:设备处于活动状态。
有什么建议吗?
目的是计算成对字符串的相似性,这意味着对于文件中的每一行,我想计算与其他每一行的Levenshtein距离。
编辑:在这个问题8个月后提出的一个相关问题有许多有用的答案和评论。要更深入地了解python逻辑,请阅读以下相关问题:如何在python中逐行读取文件?
两种内存高效方法按顺序排列(第一种是最好的)-
python 2.5及以上版本支持with -的使用
如果你真的想控制读取量,可以使用yield
1. with的用法
With是读取大文件的一种漂亮而有效的python方法。优点- 1)文件对象在使用执行块退出后自动关闭。2) with块内部的异常处理。3) memory for循环逐行遍历f文件对象。在内部它做缓冲IO(优化昂贵的IO操作)和内存管理。
with open("x.txt") as f:
for line in f:
do something with data
2. 产量的使用
有时,人们可能希望对每次迭代中读取的量进行更细粒度的控制。在这种情况下,使用iter & yield。注意,使用这种方法需要在结束时显式地关闭文件。
def readInChunks(fileObj, chunkSize=2048):
"""
Lazy function to read a file piece by piece.
Default chunk size: 2kB.
"""
while True:
data = fileObj.read(chunkSize)
if not data:
break
yield data
f = open('bigFile')
for chunk in readInChunks(f):
do_something(chunk)
f.close()
陷阱和为了完整性——下面的方法对于读取大文件来说不是那么好或不那么优雅,但请阅读以获得全面的理解。
在Python中,从文件中读取行最常见的方法是执行以下操作:
for line in open('myfile','r').readlines():
do_something(line)
但是,当完成此操作时,readlines()函数(与read()函数相同)将整个文件加载到内存中,然后对其进行迭代。对于大文件,稍微好一点的方法(上面提到的两种方法是最好的)是使用fileinput模块,如下所示:
import fileinput
for line in fileinput.input(['myfile']):
do_something(line)
fileinput.input()调用按顺序读取行,但在读取后不将它们保存在内存中,甚至只是这样,因为python中的file是可迭代的。
参考文献
带有语句的Python
来自python文档fileinput.input():
这将遍历sys. exe中列出的所有文件的行。Argv[1:],默认为sys。如果列表为空,则输入
进一步,函数的定义为:
fileinput.FileInput([files[, inplace[, backup[, mode[, openhook]]]]])
字里行间,这告诉我文件可以是一个列表,所以你可以有这样的东西:
for each_line in fileinput.input([input_file, input_file]):
do_something(each_line)
更多信息请参见这里
我强烈建议不要使用默认的文件加载,因为它非常慢。你应该研究一下numpy函数和IOpro函数(例如numpy.loadtxt())。
http://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html
https://store.continuum.io/cshop/iopro/
然后你可以把你的成对操作分解成几个块:
import numpy as np
import math
lines_total = n
similarity = np.zeros(n,n)
lines_per_chunk = m
n_chunks = math.ceil(float(n)/m)
for i in xrange(n_chunks):
for j in xrange(n_chunks):
chunk_i = (function of your choice to read lines i*lines_per_chunk to (i+1)*lines_per_chunk)
chunk_j = (function of your choice to read lines j*lines_per_chunk to (j+1)*lines_per_chunk)
similarity[i*lines_per_chunk:(i+1)*lines_per_chunk,
j*lines_per_chunk:(j+1)*lines_per_chunk] = fast_operation(chunk_i, chunk_j)
以块方式加载数据,然后对其进行矩阵操作,几乎总是比一个元素一个元素地加载数据快得多!!
Katrielalex提供了打开和读取一个文件的方法。
不管你的算法是如何运行的,它会为文件的每一行读取整个文件。这意味着,如果N是文件中的行数,那么读取文件的总量(以及计算Levenshtein距离)将是N*N。由于您关心文件大小,并且不想将其保存在内存中,因此我关心的是所产生的二次运行时。你的算法属于O(n^2)类算法,通常可以通过专门化来改进。
我怀疑您已经知道这里内存与运行时的权衡,但是您可能想要研究是否有一种并行计算多个Levenshtein距离的有效方法。如果是这样的话,在这里分享你的解决方案会很有趣。
你的文件有多少行,你的算法必须在什么样的机器(mem和cpu功率)上运行,以及容忍的运行时间是多少?
代码如下所示:
with f_outer as open(input_file, 'r'):
for line_outer in f_outer:
with f_inner as open(input_file, 'r'):
for line_inner in f_inner:
compute_distance(line_outer, line_inner)
但问题是你如何存储距离(矩阵?),你能获得一个优势准备例如outer_line处理,或缓存一些中间结果以供重用。
需要经常从上一个位置读取一个大文件?
我创建了一个脚本,用于每天多次删除Apache access.log文件。
所以我需要在最后一次执行期间解析的最后一行上设置位置光标。
为此,我使用了file.seek()和file.seek()方法,它们允许将光标存储在文件中。
我的代码:
ENCODING = "utf8"
CURRENT_FILE_DIR = os.path.dirname(os.path.abspath(__file__))
# This file is used to store the last cursor position
cursor_position = os.path.join(CURRENT_FILE_DIR, "access_cursor_position.log")
# Log file with new lines
log_file_to_cut = os.path.join(CURRENT_FILE_DIR, "access.log")
cut_file = os.path.join(CURRENT_FILE_DIR, "cut_access", "cut.log")
# Set in from_line
from_position = 0
try:
with open(cursor_position, "r", encoding=ENCODING) as f:
from_position = int(f.read())
except Exception as e:
pass
# We read log_file_to_cut to put new lines in cut_file
with open(log_file_to_cut, "r", encoding=ENCODING) as f:
with open(cut_file, "w", encoding=ENCODING) as fw:
# We set cursor to the last position used (during last run of script)
f.seek(from_position)
for line in f:
fw.write("%s" % (line))
# We save the last position of cursor for next usage
with open(cursor_position, "w", encoding=ENCODING) as fw:
fw.write(str(f.tell()))