读取大文件时跳过一长行以避免 MemoryError?
Skip a long line when reading a big file to avoid MemoryError?
我需要扫描两个大的txt文件(都大约100GB,10亿行,几列)并取出某一列(写入新文件)。文件看起来像这样
ID*DATE*provider
1111*201101*1234
1234*201402*5678
3214*201003*9012
...
我的Python脚本是
N100 = 10000000 ## 1% of 1 billion rows
with open("myFile.txt") as f:
with open("myFile_c2.txt", "a") as f2:
perc = 0
for ind, line in enumerate(f): ## <== MemoryError
c0, c1, c2 = line.split("*")
f2.write(c2+"\n")
if ind%N100 == 0:
print(perc, "%")
perc+=1
现在上面的脚本 运行 对于一个文件来说很好,但对于另一个文件来说卡在了 62%。错误消息显示 MemoryError
for for ind, line in enumerate(f):
。我在不同内存的不同服务器上试了几次,错误都是一样的,都是62%。我等了几个小时来监控 RAM,它在 62% 时爆炸到 28GB(总计=32GB)。所以我想在那个文件中有一行太长了(可能没有以 \n
结尾?)因此 Python 在尝试将其读取到 RAM 时卡住了。
所以我的问题是,在我访问我的数据提供者之前,我可以做些什么来检测错误行并以某种方式让 around/skip 将其作为一大行来读取?感谢任何建议!
编辑:
从 'error line' 开始的文件可能与另一个行分隔符而不是 \n
混在一起。如果是这样,我可以检测到 sep 行并继续提取我想要的列,而不是丢弃它们吗?谢谢!
此(未经测试的)代码可能会解决您的问题。它将每次读取的输入限制为 1,000,000 字节,以减少其最大内存消耗。
请注意,此代码 return 是每一行的 前 百万个字符。长线的处理方式还有其他可能:
- return前百万字符
- return 最后一百万字符
- 完全跳过该行,可选择记录该行,或者
- 引发异常。
#UNTESTED
def read_start_of_line(fp):
n = int(1e6)
tmp = result = fp.readline(n)
while tmp and tmp[-1] != '\n':
tmp = fp.readline(n)
return result
N100 = 10000000 ## 1% of 1 billion rows
with open("myFile.txt") as f:
with open("myFile_c2.txt", "a") as f2:
perc = 0
for ind, line in enumerate(iter(lambda: read_start_of_line(f), '')):
c0, c1, c2 = line.split("*")
f2.write(c2+"\n")
if ind%N100 == 0:
print(perc, "%")
perc+=1
指定最大块大小解决了内存溢出的问题,同时仍然允许您处理整个文件。以下生成器函数应该可以帮助您做到这一点:
def chunks(f, bufsize):
while True:
chunk = f.readline(bufsize)
if not chunk:
break
yield chunk
if chunk[-1] == "\n":
break
def lines(path, bufsize):
with open(path) as f:
pos = -1
while f.tell() > pos:
pos = f.tell()
c = chunks(f, bufsize)
yield c
for _ in c:
pass
下面是一个如何只读取每行前 20 个字符的示例:
import itertools
for i, line in enumerate(lines("./core/scrape.js", 10)):
print(i, end=": ")
print(''.join(itertools.islice(line, 2)).rstrip())
输出类似于:
0: /**
1: * Document scraper/
2: *
3: * @author Branden H
4: * @license MIT
5: *
6: */
7:
8: var promise = requir
9: var fs = promise.pro
10: var _ = require("lod
11: var util = require("
12: const path = require
我需要扫描两个大的txt文件(都大约100GB,10亿行,几列)并取出某一列(写入新文件)。文件看起来像这样
ID*DATE*provider
1111*201101*1234
1234*201402*5678
3214*201003*9012
...
我的Python脚本是
N100 = 10000000 ## 1% of 1 billion rows
with open("myFile.txt") as f:
with open("myFile_c2.txt", "a") as f2:
perc = 0
for ind, line in enumerate(f): ## <== MemoryError
c0, c1, c2 = line.split("*")
f2.write(c2+"\n")
if ind%N100 == 0:
print(perc, "%")
perc+=1
现在上面的脚本 运行 对于一个文件来说很好,但对于另一个文件来说卡在了 62%。错误消息显示 MemoryError
for for ind, line in enumerate(f):
。我在不同内存的不同服务器上试了几次,错误都是一样的,都是62%。我等了几个小时来监控 RAM,它在 62% 时爆炸到 28GB(总计=32GB)。所以我想在那个文件中有一行太长了(可能没有以 \n
结尾?)因此 Python 在尝试将其读取到 RAM 时卡住了。
所以我的问题是,在我访问我的数据提供者之前,我可以做些什么来检测错误行并以某种方式让 around/skip 将其作为一大行来读取?感谢任何建议!
编辑:
从 'error line' 开始的文件可能与另一个行分隔符而不是 \n
混在一起。如果是这样,我可以检测到 sep 行并继续提取我想要的列,而不是丢弃它们吗?谢谢!
此(未经测试的)代码可能会解决您的问题。它将每次读取的输入限制为 1,000,000 字节,以减少其最大内存消耗。
请注意,此代码 return 是每一行的 前 百万个字符。长线的处理方式还有其他可能:
- return前百万字符
- return 最后一百万字符
- 完全跳过该行,可选择记录该行,或者
- 引发异常。
#UNTESTED
def read_start_of_line(fp):
n = int(1e6)
tmp = result = fp.readline(n)
while tmp and tmp[-1] != '\n':
tmp = fp.readline(n)
return result
N100 = 10000000 ## 1% of 1 billion rows
with open("myFile.txt") as f:
with open("myFile_c2.txt", "a") as f2:
perc = 0
for ind, line in enumerate(iter(lambda: read_start_of_line(f), '')):
c0, c1, c2 = line.split("*")
f2.write(c2+"\n")
if ind%N100 == 0:
print(perc, "%")
perc+=1
指定最大块大小解决了内存溢出的问题,同时仍然允许您处理整个文件。以下生成器函数应该可以帮助您做到这一点:
def chunks(f, bufsize):
while True:
chunk = f.readline(bufsize)
if not chunk:
break
yield chunk
if chunk[-1] == "\n":
break
def lines(path, bufsize):
with open(path) as f:
pos = -1
while f.tell() > pos:
pos = f.tell()
c = chunks(f, bufsize)
yield c
for _ in c:
pass
下面是一个如何只读取每行前 20 个字符的示例:
import itertools
for i, line in enumerate(lines("./core/scrape.js", 10)):
print(i, end=": ")
print(''.join(itertools.islice(line, 2)).rstrip())
输出类似于:
0: /**
1: * Document scraper/
2: *
3: * @author Branden H
4: * @license MIT
5: *
6: */
7:
8: var promise = requir
9: var fs = promise.pro
10: var _ = require("lod
11: var util = require("
12: const path = require