在Windows上的巨大CSV文件中替换字符串



我有一个巨大的CSV文件,大小超过250GB。我想替换字符"(一无所有)。我觉得它应该很简单,但是文件大小确保没有编辑器打开文件。

我也可以使用python进行以下代码:

with open(file) as src:
    lines = src.read()
print(lines.replace(old_string, new_string))

但是此代码要求该文件在内存中。

一个选项是通过编写替换不需要字符的行来创建另一个文件。但这意味着在磁盘上具有几乎相同大小的磁盘上的两个文件。不幸的是,我在服务器上没有那么多磁盘空间。

因此,有没有办法覆盖行并替换字符而不创建新文件?

一些示例CSV线是:

abc,"('91730', 'd9973')",1
def,"('91210', 'd9943')",1
ghi,"('91670', 'd9293')",1

您可以通过这样的文件行迭代:

with open(file, 'rt') as src:
    for line in src:
        print(line.replace('"', '').replace('(', ''))

但是我将使用CSV模块的CSVReader。

作为创建第二个文件的妥协,您可以用空格替换所有有问题的字符。这样,文件将保持相同的大小,而不需要重写。Python的translate()功能很快这样做:

import string
table = string.maketrans('(")', '   ')
block_size = 10000000
start_pos = 0        
with open('input.csv', 'r+b') as f_input:
    while True:
        f_input.seek(start_pos)
        block = f_input.read(block_size)
        if len(block):
            f_input.seek(start_pos)
            f_input.write(block.translate(table))
        else:
            break
        start_pos += block_size

这将为您提供一个看起来像:

的输出文件
abc,  '91730', 'd9973'  ,1
def,  '91210', 'd9943'  ,1
ghi,  '91670', 'd9293'  ,1

我会建议您只需处理"原样"文件:

import csv
with open('input.csv', 'rb') as f_input:
    for row in csv.reader(f_input):
        data = re.match(r"('(.*?)', '(.*?)'", row[1]).groups()
        row[1] = data[0]
        row.insert(1, data[1])
        print row

对于您的数据,这将显示:

['abc', 'd9973', '91730', '1']
['def', 'd9943', '91210', '1']
['ghi', 'd9293', '91670', '1']

如果您的唯一选项是编辑到适当的文件,则可以执行以下操作:

  • 以二进制模式打开文件
  • 在缓冲区中读取一块数据(例如4096字节,即页面大小)
  • 从该缓冲区中删除字符,或通过字节写入第二个缓冲区,跳过不需要的字符。
  • 然后将第二个缓冲区写入同一打开文件后,将文件指针重新定位到正确的位置(使用seek())。(当然,只有新尺寸,而不是完整的4096字节)
  • 继续重复直到文件末尾,然后将文件(将新文件大小设置)缩小到新书面数据的大小。

因此,您必须跟踪2个文件位置:当前的read_buffer位置和文件中的当前write_buffer位置,每次读取或写入时,请重新定位文件指针。

这也将在当时的阅读和编写字节上工作,但是我不知道(好)Python正在缓冲数据,因此可以慢慢进行。

缓冲区的一种替代方法是使用内存映射。

我会提供一些示例代码,但我没有python(而且我不太了解Python)。

,但是请确保您首先进行一些较小的测试,因为您不会在问题时留下原始文件的副本。

有关读取二进制文件的示例,请参阅此问题。

除非您使用64位版本的Python,否则我将不依赖seek能够将指针定位在2或4 GB后面。我很确定它不能在Python 2 32位上使用,因为标准图书馆说(强调我的):

file.seek(offset [,when whOne]): 设置文件的当前位置,类似于stdio的fseek()

在32位系统上,FSEEK仅采用32位参数...无论如何,fseek在Python 3中可能是安全的,因为整数是长整数,并且对STDIO FSEEK的引用已从文档中删除 - 但是,但是我强烈建议您两次控制它...

这样,我将尝试两次打开文件,一次以" RB"模式打开文件,以便对其进行读取指针,然后以" R B"模式以其上的写入指针。在这里,它可能会根据OS不起作用,但是许多过程允许单个进程在同一文件上获取多个文件描述符。对于Python2,代码与 @Martinevans的答案没有太大区别:

table = string.maketrans('(")', '   ')
block_size = 10000000
start_pos = 0        
with open('input.csv', 'rb') as f_input, open('input.csv', 'r+b') as f_output:
    while True:
        block = f_input.read(block_size)
        if len(block):
            f_input.seek(start_pos)
            f_output.write(block.translate(table))
        else:
            break

相关内容

  • 没有找到相关文章

最新更新