Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在Windows上替换大型csv文件中的字符串_Python_Csv - Fatal编程技术网

Python 在Windows上替换大型csv文件中的字符串

Python 在Windows上替换大型csv文件中的字符串,python,csv,Python,Csv,我有一个巨大的csv文件,大小超过250GB。我想替换字符“和(没有)。我觉得应该是非常直接的,但是文件大小确保没有编辑器打开文件 我还可以使用python,可以使用以下代码: with open(file) as src: lines = src.read() print(lines.replace(old_string, new_string)) 但此代码要求文件位于内存中 一种选择是创建另一个文件,通过写行替换不需要的字符。但这意味着磁盘上有两个大小几乎相同的文件。不幸的是,我在

我有一个巨大的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('(', ''))

但我会使用来自的csvreader。

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

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

但我会使用来自的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']

作为创建第二个文件的一种折衷方法,您可以将所有有问题的字符替换为空格。这样,文件大小将保持不变,无需重写。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字节)
  • 继续重复,直到文件结束,然后将文件(设置新文件大小)缩小到新写入数据的大小
因此,您必须跟踪两个文件位置:文件中的当前读取缓冲区位置和当前写入缓冲区位置,并且每次读取或写入时,都要重新定位文件指针

这也可以同时读取和写入一个字节,但我不知道Python缓冲数据的效果如何,所以速度可能会慢一些

缓冲区的另一种选择是使用内存映射

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

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


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

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

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

这也可以同时读取和写入一个字节,但我不知道Python缓冲数据的效果如何,所以速度可能会慢一些

缓冲区的另一种选择是使用内存映射

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

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


有关读取二进制文件的示例,请参见。

除非您使用64位版本的Python,否则我不会依靠
seek
将指针定位在2或4 Gb之后。我非常确定它无法在Python 2 32位上工作,因为标准库文档(强调我的文档):

file.seek(偏移量[,何处]): 设置文件的当前位置,如stdio的fseek()

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

所以我会尝试打开文件两次,一次在“rb”模式下打开一个读指针,一次在“r+b”模式下打开“模式上有一个写指针。根据操作系统的不同,这里可能也不起作用,但许多操作系统允许单个进程在同一个文件上获取多个文件描述符。代码与@MartinEvans对Python2的回答没有太大区别:

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

除非您使用64位版本的Python,否则我不会指望
seek
能够将指针定位在2或4 Gb之后。我非常确定它不能在Python 2 32位上工作,因为标准库文档说(强调我的):

file.seek(偏移量[,何处]): 设置文件的当前位置,