如何逐行读取大文件行

问题描述 投票:491回答:10

我想遍历整个文件的每一行。要做到这一点的方法之一是通过读取整个文件,将其保存到列表,然后去了关注的线。此方法使用大量的内存,所以我要寻找一个替代。

到目前为止我的代码:

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)

执行该代码给出了一个错误信息:device active

有什么建议么?

目的是为了计算成对串相似,意为在文件中的每一行,我要计算与所有其他线的Levenshtein距离。

python file-read
10个回答
1232
投票

读取文件的正确,充分Python的方式如下:

with open(...) as f:
    for line in f:
        # Do something with 'line'

with语句处理打开和关闭文件,其中包括了一个异常在内部块中引发。该for line in f把文件对象f视为可迭代,它会自动使用缓冲I / O和内存管理,所以你不必担心大文件。

应该有一个 - 并且最好只有一个 - 明显的方法来做到这一点。


-2
投票

最好的方式来读取大文件,一行行是使用Python枚举函数

with open(file_name, "rU") as read_file:
    for i, row in enumerate(read_file, 1):
        #do something
        #i in line of that line
        #row containts all data of that line

122
投票

在按照排名顺序两个内存有效的方法(第一个是最好的) -

  1. 使用with - 从蟒2.5和上述支持
  2. 使用yield的,如果你真的想有过多少读控制

1.使用with

with是读取大文件的好的和高效的Python的方式。优点 - 1)文件对象从with执行块退出后自动关闭。 2)with块内的异常处理。 3)通过由线for文件对象行存储器f循环迭代。内部它缓冲IO(对昂贵IO操作进行了优化)和存储器管理。

with open("x.txt") as f:
    for line in f:
        do something with data

2.使用yield

有时,一个可能要超过多少在每个迭代阅读更细粒度的控制。在这种情况下使用iteryield。注意:用这种方法一个明确需要关闭文件结尾。

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 chuck 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()调用读取线顺序,但不会保留在内存中,他们一直阅读甚至干脆所以这之后,因为file在python是迭代。

参考

  1. Python with statement

37
投票

剥离换行符:

with open(file_path, 'rU') as f:
    for line_terminated in f:
        line = line_terminated.rstrip('\n')
        ...

随着universal newline support所有文本文件中的行会显得与'\n'被终止,无论在文件中,'\r''\n',或'\r\n'的终结。

编辑 - 指定通用换行符支持:

  • 在Unix的Python 2 - open(file_path, mode='rU') - 需[感谢@Dave]
  • open(file_path, mode='rU') - - 在Windows上的Python 2可选
  • Python的3 - open(file_path, newline=None) - 可选

newline参数只在Python 3,缺省支持到None。该mode参数默认为在所有情况下'r'。该U是在Python 3不赞成在Python 2在Windows上一些其他的机制似乎翻译\r\n\n

文档:

为了保持自然行终止:

with open(file_path, 'rb') as f:
    with line_native_terminated in f:
        ...

二进制模式还可以将文件解析与in线。每一行都会有它在文件中的任何终止。

由于@katrielalexanswer,Python的open()文档,并iPython实验。


17
投票

这是读取Python中的文件的可能方式:

f = open(input_file)
for line in f:
    do_stuff(line)
f.close()

它不分配的完整列表。它遍历行。


10
投票

一些背景前面到哪里我来自哪里。代码片段是在最后。

当我可以,我更喜欢使用像H2O的开源工具做超高性能并行CSV文件读取,但是这个工具在功能设置限制。我最后写了很多的代码输送到水簇的监督学习正确的之前创建的数据科学的管道。

我一直显著更快的读取来自UCI回购像8GB HIGGS数据集的文件,甚至40GB的CSV文件数据的科学目的,通过添加大量与多道库的池对象和地图功能的并行性。对于最近邻搜索,并且还DBSCAN和马尔可夫聚类算法例如聚类需要一些并行编程技巧绕过一些严重的挑战性存储器和挂钟时间的问题。

我平时喜欢打破文件逐行成使用GNU工具,然后再水珠,文件匹配他们全部找到,并在Python程序并行阅读部分。我使用类似常用的1000+部分文件。做这些技巧可以帮助非常具有处理速度和内存的限制。

熊猫dataframe.read_csv是单线程的,所以你可以做这些技巧,使大熊猫通过运行图()的并行执行相当快。您可以使用HTOP地看到,与普通的老顺序大熊猫dataframe.read_csv,100%的CPU上只有一个核心是pd.read_csv实际的瓶颈,而不是磁盘的。

我要补充我使用快速的显卡总线上的SSD,而不是一个纺纱HD SATA6总线上,再加上16个CPU内核。

另外,我发现伟大的作品在某些应用中的另一种技术是并行CSV文件读取都在一个巨大的文件,开始在不同的每个工人偏移到文件,而不是预裂一个大文件分成许多部分文件。使用Python的文件查找(),并告诉()在每个并行工作来读取带大的文本文件,在不同的字节偏移的大文件开始字节和终止字节的位置,都在同一时间同时进行。你可以在字节的正则表达式的findall,并返回换行的计数。这是一个部分和。最后总结部分和获取全局和当工人后的地图函数返回完成。

下面是使用并行字节偏移招一些示例基准:

我用2个文件:HIGGS.csv是8 GB。它是从UCI机器学习库。 all_bin的.csv为40.4 GB,是从我目前的项目。我用两个程序:GNU厕所程序,它自带的Linux,以及我公司开发的纯Python fastread.py程序。

HP-Z820:/mnt/fastssd/fast_file_reader$ ls -l /mnt/fastssd/nzv/HIGGS.csv
-rw-rw-r-- 1 8035497980 Jan 24 16:00 /mnt/fastssd/nzv/HIGGS.csv

HP-Z820:/mnt/fastssd$ ls -l all_bin.csv
-rw-rw-r-- 1 40412077758 Feb  2 09:00 all_bin.csv

ga@ga-HP-Z820:/mnt/fastssd$ time python fastread.py --fileName="all_bin.csv" --numProcesses=32 --balanceFactor=2
2367496

real    0m8.920s
user    1m30.056s
sys 2m38.744s

In [1]: 40412077758. / 8.92
Out[1]: 4530501990.807175

这是一些4.5 GB / s的,或45 Gb / s的,文件啜速度。那是不是没有旋转的硬盘,我的朋友。这实际上是一个三星PRO 950 SSD。

以下是相同的文件被线计数由GNU WC,一个纯C编译的程序的速度基准。

什么是酷的是你可以看到我的纯Python程序在这种情况下,基本上是相匹配的GNU编译WC C程序的速度。 Python是解释但是C编译,所以这是一个非常有趣的速度的壮举,我想你会同意。当然,厕所确实需要改变,以并行程序,然后它会真的打败袜子我的Python程序。但是,因为它代表今天,GNU厕所只是一个顺序程序。你做你能做的事,和Python可以做今天平行。用Cython编译也许能帮助我(对于一些其他时间)。另外内存映射文件中没有讨论。

HP-Z820:/mnt/fastssd$ time wc -l all_bin.csv
2367496 all_bin.csv

real    0m8.807s
user    0m1.168s
sys 0m7.636s


HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000

real    0m2.257s
user    0m12.088s
sys 0m20.512s

HP-Z820:/mnt/fastssd/fast_file_reader$ time wc -l HIGGS.csv
11000000 HIGGS.csv

real    0m1.820s
user    0m0.364s
sys 0m1.456s

结论:相比于一个C程序的速度有利于纯Python程序。然而,这还不够好,使用纯Python程序在C程序中,至少linecounting目的。一般来说,技术可以用于其它文件处理,所以这个Python代码还是不错的。

问:请问编译正则表达式只是一个时间并将它传递给所有工人将提高速度?答:正则表达式预编译不会在这个应用程序的帮助。我想,其原因是这一进程的序列化和创造对所有工作人员的开销支配。

还有一件事。是否平行CSV文件的阅读,甚至帮助吗?是磁盘瓶颈,或者是它的CPU?计算器上的很多所谓的收视率最高的答案包含共同开发智慧,你只需要一个线程读取文件,最好你能做到的,他们说。他们是肯定有关系吗?

让我们来看看:

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000

real    0m2.256s
user    0m10.696s
sys 0m19.952s

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=1
11000000

real    0m17.380s
user    0m11.124s
sys 0m6.272s

哦,是的,是的,它确实。并行文件读取工作得很好。好,你去吧!

PS。在某些情况下,你想知道,如果什么balanceFactor使用单一的工作进程时为2?嗯,这是可怕的:

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=2
11000000

real    1m37.077s
user    0m12.432s
sys 1m24.700s

该fastread.py Python程序的关键部分:

fileBytes = stat(fileName).st_size  # Read quickly from OS how many bytes are in a text file
startByte, endByte = PartitionDataToWorkers(workers=numProcesses, items=fileBytes, balanceFactor=balanceFactor)
p = Pool(numProcesses)
partialSum = p.starmap(ReadFileSegment, zip(startByte, endByte, repeat(fileName))) # startByte is already a list. fileName is made into a same-length list of duplicates values.
globalSum = sum(partialSum)
print(globalSum)


def ReadFileSegment(startByte, endByte, fileName, searchChar='\n'):  # counts number of searchChar appearing in the byte range
    with open(fileName, 'r') as f:
        f.seek(startByte-1)  # seek is initially at byte 0 and then moves forward the specified amount, so seek(5) points at the 6th byte.
        bytes = f.read(endByte - startByte + 1)
        cnt = len(re.findall(searchChar, bytes)) # findall with implicit compiling runs just as fast here as re.compile once + re.finditer many times.
    return cnt

对于PartitionDataToWorkers DEF是否只是普通的顺序代码。我离开它,以防其他人想要得到什么并行编程是像一些做法。我送出了免费的困难部分:测试和工作并行代码,为您的学习效益。

感谢:开源H2O项目,由阿诺和克里夫和H2O的工作人员为他们的伟大的软件和教学视频,这​​为我提供了灵感,这个纯Python高性能并行字节偏移读者如上图所示。 H2O确实用java并行文件的阅读,是蟒蛇和R程序调用,而且是快疯了,比地球上任何事物都快在读大的CSV文件。


5
投票

Katrielalex用于打开和读取一个文件的方式。

但是你的算法去的方式读取文件的每一行的整个文件。这意味着读取文件整体的量 - 和计算Levenshtein distance - 将完成N * N如果N是文件中的行的数量。既然你担心文件大小,并且不希望保留在内存中,我关注的产生quadratic runtime。你的算法是在为O(n ^ 2)类的,而这往往与专业化得到改善的算法。

我怀疑你已经知道的记忆与运行时这里的权衡,但也许你会想,以调查是否有计算并行多莱文斯坦距离的有效方法。如果是的话这将是有趣在这里分享您的解决方案。

多少行做你的文件有,和什么样的机器(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进行处理,或高速缓存重新使用一些中间结果。


3
投票
#Using a text file for the example
with open("yourFile.txt","r") as f:
    text = f.readlines()
for line in text:
    print line
  • 打开文件进行读取(R)
  • 读取整个文件,每行保存到列表(文本)
  • 通过列表打印每一行循环。

如果你想,例如,查看特定线的长度大于10,工作与你已经拥有。

for line in text:
    if len(line) > 10:
        print line

2
投票

fileinput.input()Python文档:

这种迭代的sys.argv[1:]列出的所有文件的线条,默认为sys.stdin如果列表是空的

进一步,该函数的定义是:

fileinput.FileInput([files[, inplace[, backup[, mode[, openhook]]]]])

字里行间,这告诉我,files可以是一个列表,所以你可以有这样的:

for each_line in fileinput.input([input_file, input_file]):
  do_something(each_line)

here了解更多信息


2
投票

我会强烈建议不使用默认文件加载,因为它是缓慢的窘况。你应该看看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) 

它几乎总是更快地加载在大块数据,然后它做矩阵运算比元素做元素!

© www.soinside.com 2019 - 2024. All rights reserved.