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

时间:2017-03-14 16:01:08

标签: python 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

4 个答案:

答案 0 :(得分:0)

你可以像这样迭代文件的行:

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

但我会使用CSV module中的csvreader。

答案 1 :(得分:0)

作为创建第二个文件的折衷方案,您可以用空格替换所有有问题的字符。这样文件将保持相同的大小,不需要重写。 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

我建议您只处理文件"按原样#34;如果可能的话:

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']

答案 2 :(得分:0)

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

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

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

这也可以在当时读取和写入一个字节,但我不知道(好)Python是如何缓冲数据的,所以它可能会更慢。

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

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

但请确保先进行一些较小的测试,因为如果出现问题,您将无法获得原始文件的副本。

有关读取二进制文件的示例,请参阅this question

答案 3 :(得分:0)

除非你使用64位版本的Python,否则我不会依赖seek能够将指针放在2或4 Gb后面。我很确定它无法在Python 2 32位上运行,因为标准库文档说(强调我的):

  

file.seek(offset [,whence]):       设置文件的当前位置,,例如stdio&#fseek()

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

所以我会尝试打开文件两次,一次在" rb"模式在其上有一个读指针,一旦在" r + b"模式,在其上有一个写指针。在这里它可能不起作用取决于操作系统,但许多允许单个进程在同一文件上获取多个文件描述符。对于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
相关问题