我有一个~2亿行,7列csv文件。我需要删除第2636759行。 这个文件是7.7GB,超过内存容量。我对R最熟悉,但也可以在python或bash中执行此操作。
我无法在一次操作中读取或写入此文件。在磁盘上逐步构建此文件的最佳方法是什么,而不是尝试在内存中全部执行此操作?
我试图在SO上找到它,但只能找到如何使用足够小的文件来读取/写入内存,或者使用位于文件开头的行。
答案 0 :(得分:7)
一个python解决方案:
import os
with open('tmp.csv','w') as tmp:
with open('file.csv','r') as infile:
for linenumber, line in enumerate(infile):
if linenumber != 10234:
tmp.write(line)
# copy back to original file. You can skip this if you don't
# mind (or prefer) having both files lying around
with open('tmp.csv','r') as tmp:
with open('file.csv','w') as out:
for line in tmp:
out.write(line)
os.remove('tmp.csv') # remove the temporary file
这会复制数据,如果磁盘空间有问题,这可能不是最佳数据。在没有将整个文件首先加载到RAM中的情况下,写入会更复杂
关键是python自然支持处理files as iterables。这意味着它可以进行延迟评估,并且您永远不需要一次将整个事物保存在内存中
我喜欢这个解决方案,如果您的主要关注点不是原始速度,因为您可以使用任何条件测试替换行linenumber != VALUE
,例如,过滤掉包含特定日期的行
test = lambda line : 'NOVEMBER' in line
with open('tmp.csv','w') as tmp:
...
if test(line):
...
In-place read-writes和memory mapped file objects(可能相当快)将需要更多的簿记
答案 1 :(得分:2)
使用sed '2636759d' file.csv > fixedfile.csv
作为40,001行1.3G csv的测试,以40,000
方式删除行0m35.710s
。来自@en_Knight的python解决方案的内容(只是剥离行并写入临时文件)对于同一个文件来说快了大约2秒。
修改确定sed
(或某些实施)可能不起作用(根据提问者的反馈)
您可以通过简单的bash从n
行N
的文件中删除行file.csv
,您可以执行head -[n-1] file.csv > file_fixed.csv
和tail -[N-n] file.csv >> file_fixed.csv
(在这两个中,括号中的表达式都用普通数字代替。
要做到这一点,尽管你需要知道N
。 python解决方案更好......
答案 2 :(得分:1)
您也可以R
中的readLines
一行阅读一行,然后使用writeLines
python
执行此操作
对于与con <- file('test.csv', 'r')
out_con <- file('tmp.csv', 'w')
bad_line <- 2636759
ctr <- 1
while (length(line <- readLines(con, n=1, warn=FALSE)) > 0){
if (ctr != bad_line)
writeLines(line, out_con)
ctr <- ctr + 1
}
中的解决方案类似的解决方案:
sed
但请注意, MUCH 比python慢(在40,000行文件中需要~3m40s n
需要30秒)。可能会增加块大小sed
会加快速度,但python
或sTHead += @"<TH>" + col.ColumnName + @"</TH>";
似乎更容易。