Python 在Windows上替换大型csv文件中的字符串
我有一个巨大的csv文件,大小超过250GB。我想替换字符“和(没有)。我觉得应该是非常直接的,但是文件大小确保没有编辑器打开文件 我还可以使用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)) 但此代码要求文件位于内存中 一种选择是创建另一个文件,通过写行替换不需要的字符。但这意味着磁盘上有两个大小几乎相同的文件。不幸的是,我在
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字节,即页面大小)
- 从该缓冲区中删除字符,或将该缓冲区逐字节写入第二个缓冲区,跳过不需要的字符
- 然后在将文件指针重新定位到正确位置(使用
)后,将第二个缓冲区写入同一打开的文件。(当然,只有新的大小,而不是完整的4096字节)seek()
- 继续重复,直到文件结束,然后将文件(设置新文件大小)缩小到新写入数据的大小
有关读取二进制文件的示例,请参阅。如果您唯一的选择是就地编辑文件,则可以执行以下操作:
- 以二进制模式打开文件
- 读取缓冲区中的数据块(例如4096字节,即页面大小)
- 从该缓冲区中删除字符,或将该缓冲区逐字节写入第二个缓冲区,跳过不需要的字符
- 然后在将文件指针重新定位到正确位置(使用
)后,将第二个缓冲区写入同一打开的文件。(当然,只有新的大小,而不是完整的4096字节)seek()
- 继续重复,直到文件结束,然后将文件(设置新文件大小)缩小到新写入数据的大小
有关读取二进制文件的示例,请参见。除非您使用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(偏移量[,何处]):
设置文件的当前位置,