使用"for line in file object"方法读取文件

1 投票
5 回答
3726 浏览
提问于 2025-04-17 08:05

我正在寻找处理超大文件的最佳方法。这里我试了一下:

for line in f:

我的脚本的一部分如下:

o=gzip.open(file2,'w')
LIST=[]
f=gzip.open(file1,'r'):
for i,line in enumerate(f):
   if i%4!=3:
      LIST.append(line)

   else:
      LIST.append(line)
      b1=[ord(x) for x in line]
      ave1=(sum(b1)-10)/float(len(line)-1)
      if (ave1 < 84):
         del LIST[-4:]
output1=o.writelines(LIST)

我的 file1 大约有10GB;当我运行这个脚本时,内存使用量不断增加,最终达到15GB,却没有任何输出。这意味着计算机还是在试图把整个文件都读入内存,对吧?这跟使用 readlines() 没什么区别。

不过在这篇帖子里: 不同的方法来读取Python中的大数据 Srika告诉我: for line in f 会把文件对象 f 当作一个可迭代的对象,这样就会自动使用缓冲输入输出和内存管理,所以你不需要担心大文件的问题。

但显然我还是需要担心大文件……我真的很困惑。 谢谢。

补充: 我的数据每4行算作一组。 我的目的是对每4行进行一些计算;根据这个计算,决定是否需要把这4行添加到结果中。所以写入行是我的主要目的。

5 个回答

0

好吧,你已经从其他评论和回答中知道了你的问题,但我还是简单说一下。

你现在一次只把一行读入内存,但你却把很多这些行存储在内存中,因为你把它们加到了一个列表里。

为了避免这种情况,你需要把一些东西存储到文件系统或者数据库(也就是硬盘)里,以便后续查找,特别是当你的算法比较复杂的时候。

从我看到的情况来看,你可以很容易地逐步写出结果。也就是说,你现在用一个列表来存储有效的行,这些行是要写入输出的,还有一些临时的行,你可能会在某个时候删除。为了更有效地使用内存,你应该在确认这些临时行是有效输出后,尽快把它们写出去。

总之,使用你的列表只存储你需要进行计算的临时数据,一旦你有了一些准备好的有效数据,就可以直接把它写入硬盘,并从主内存中删除(在Python中,这意味着你不再需要引用它)。

4

内存一直在增加的原因是因为你在使用 LIST.append(line)。这实际上是把文件中的所有行都存储在一个列表里,显然这些数据都在内存中。你需要找到一种方法,不要这样累积行数据。应该是读取一行,处理完后再读取下一行。

还有一种方法是分块读取文件(实际上,一次读取一行也算是分块,1块 == 1行),也就是说,先读取文件的一小部分,处理完后再读取下一部分,依此类推。我仍然认为这是在Python中读取大文件或小文件的最佳方式。

with open(...) as f:
    for line in f:
        <do something with line>

with 语句负责打开和关闭文件,包括在内部代码块发生异常时的处理。for line in f 将文件对象 f 视为可迭代对象,这样就自动使用了缓冲输入输出和内存管理,所以你不需要担心大文件的问题。

1

看起来在这个函数的最后,你把所有读取的行都放进内存,然后立刻写入文件。也许你可以试试这个过程:

  1. 先把你需要的行读入内存(比如前3行)。
  2. 在第4行时,添加这一行并进行计算。
  3. 如果你的计算结果是你想要的,就把你收集到的值写入文件。
  4. 不管接下来发生什么,都要创建一个新的集合实例。

我还没有试过这个方法,但可能会像这样:

o=gzip.open(file2,'w')
f=gzip.open(file1,'r'):
LIST=[]

for i,line in enumerate(f):
   if i % 4 != 3:
      LIST.append(line)
   else:
      LIST.append(line)
      b1 = [ord(x) for x in line]
      ave1 = (sum(b1) - 10) / float(len(line) - 1

      # If we've found what we want, save them to the file
      if (ave1 >= 84):
         o.writelines(LIST)

      # Release the values in the list by starting a clean list to work with
      LIST = []

补充:不过考虑到你的文件很大,这种方法可能不是最佳选择,因为你需要写入很多行,但无论如何,值得一试。

撰写回答