如何在Python中逐行读取大文本文件,而不将其加载到内存中?

Bru*_*uno 218 python

我需要逐行读取一个大文件.假设文件超过5GB,我需要读取每一行,但显然我不想使用,readlines()因为它会在内存中创建一个非常大的列表.

以下代码如何适用于此案例?xreadlines本身是一个一个地读入记忆吗?是否需要生成器表达式?

f = (line for line in open("log.txt").xreadlines())  # how much is loaded in memory?

f.next()  
Run Code Online (Sandbox Code Playgroud)

另外,我可以做什么来以相反的顺序读取它,就像Linux tail命令一样?

我发现:

http://code.google.com/p/pytailer/

" python头,尾和向后读取文本文件的行 "

两者都运作得很好!

Joh*_*ooy 279

我提供了这个答案,因为Keith虽然简洁,却没有明确地关闭文件

with open("log.txt") as infile:
    for line in infile:
        do_something_with(line)
Run Code Online (Sandbox Code Playgroud)

  • @rochacbruno,它一次只读一行.当读取下一行时,前一个行将被垃圾收集,除非您在其他地方存储了对它的引用 (55认同)
  • 问题仍然是,"for infile in line"会将我的5GB线路加载到内存中?而且,我怎么能从尾巴上读? (24认同)
  • 谢谢!我找到了尾部解决方案http://stackoverflow.com/questions/5896079/python-head-tail-and-backward-read-by-lines-of-a-text-file/5896210#5896210 (4认同)
  • @bawejakunal,您是说一行太长而无法一次加载到内存中吗?这对于 _text_ 文件来说是不寻常的。您可以使用 `chunk = infile.read(chunksize)` 来读取有限大小的块,而不考虑它们的内容,而不是使用遍历行的 `for` 循环。您必须自己在块内搜索换行符。 (4认同)
  • @rochacbruno,不幸的是,以相反的顺序读取行并不容易有效地完成。通常,您希望以合理大小的块(例如千字节到兆字节)从文件末尾读取内容,并按换行符(或您平台上的任何行结束字符)进行分割 (2认同)

Kei*_*ith 53

您需要做的就是使用文件对象作为迭代器.

for line in open("log.txt"):
    do_something_with(line)
Run Code Online (Sandbox Code Playgroud)

更好的是在最近的Python版本中使用上下文管理器.

with open("log.txt") as fileobject:
    for line in fileobject:
        do_something_with(line)
Run Code Online (Sandbox Code Playgroud)

这也会自动关闭文件.

  • 那不是将整个文件加载到内存中吗? (3认同)

PTB*_*BNL 17

旧学校方法:

fh = open(file_name, 'rt')
line = fh.readline()
while line:
    # do stuff with line
    line = fh.readline()
fh.close()
Run Code Online (Sandbox Code Playgroud)

  • @prokher:是的,但我确实称之为"老派". (13认同)
  • 次要说明:对于异常安全,建议使用'with'语句,在你的情况下"open(filename,'rt')为fh:" (2认同)

Mik*_*ola 15

你最好使用迭代器.相关:http: //docs.python.org/library/fileinput.html

来自文档:

import fileinput
for line in fileinput.input("filename"):
    process(line)
Run Code Online (Sandbox Code Playgroud)

这样可以避免一次将整个文件复制到内存中.


jyo*_*das 9

请试试这个:

with open('filename','r',buffering=100000) as f:
    for line in f:
        print line
Run Code Online (Sandbox Code Playgroud)

  • 来自 Python 的官方文档:[link](https://docs.python.org/2/library/functions.html#open) 可选的缓冲参数指定文件所需的缓冲区大小:0 表示无缓冲,1 表示行缓冲,任何其他正值意味着使用(大约)该大小(以字节为单位)的缓冲区。负缓冲意味着使用系统默认值,通常为 tty 设备行缓冲,为其他文件完全缓冲。如果省略,则使用系统默认值 (5认同)

Bru*_*sky 7

我不敢相信这会像 @john-la-rooy 的答案看起来那么简单。因此,我cp使用逐行读写重新创建了该命令。速度太快了。

#!/usr/bin/env python3.6

import sys

with open(sys.argv[2], 'w') as outfile:
    with open(sys.argv[1]) as infile:
        for line in infile:
            outfile.write(line)
Run Code Online (Sandbox Code Playgroud)

  • 注意:因为 python 的 readline 标准化了行结尾,所以这会产生副作用,即将 DOS 行结尾为“\r\n”的文档转换为 Unix 行结尾为“\n”。我搜索这个主题的全部原因是我需要转换一个接收混乱行结尾的日志文件(因为开发人员盲目地使用了各种 .NET 库)。我惊讶地发现,在最初的速度测试之后,我不需要返回并“删除”线路。就已经很完美了! (4认同)

Ari*_*bib 6

如果文件中没有换行符,请执行以下操作:

with open('large_text.txt') as f:
  while True:
    c = f.read(1024)
    if not c:
      break
    print(c)
Run Code Online (Sandbox Code Playgroud)


jpp*_*jpp 5

过去 6 年里,Fire项目取得了长足的进步。它有一个简单的 API,涵盖了 pandas 功能的有用子集。

dask.dataframe负责内部分块,支持许多可并行操作,并允许您轻松将切片导出回 pandas 以进行内存中操作。

import dask.dataframe as dd

df = dd.read_csv('filename.csv')
df.head(10)  # return first 10 rows
df.tail(10)  # return last 10 rows

# iterate rows
for idx, row in df.iterrows():
    ...

# group by my_field and return mean
df.groupby(df.my_field).value.mean().compute()

# slice by column
df[df.my_field=='XYZ'].compute()
Run Code Online (Sandbox Code Playgroud)