Python中为大CSV文件追加列的实现方法(避免全量写入)
问题描述
需要在Python中给大型CSV文件追加列,要求:
- 不能使用
pandas.DataFrame.to_csv一次性写入整个内存中的矩阵(避免内存溢出) - 直接修改原文件,不生成新文件
已尝试使用csv模块的代码,但不确定如何用pandas的追加模式实现列追加。
示例CSV数据:
data1,data2,data3,data4 1,4,2,4 2,32,1,4 3,3,1,5 4,3,1,5 5,2,22,9 6,3,34,9 7,5,4,9
尝试的代码:
import csv def add_col_to_csv(csvfile,fileout,new_list): with open(csvfile, 'r') as read_f, \ open(fileout, 'w', newline='') as write_f: csv_reader = csv.reader(read_f) csv_writer = csv.writer(write_f) i = 0 for row in csv_reader: row.append(new_list[i]) csv_writer.writerow(row) i += 1 new_list1 = ['new_col',4,4,5,5,9,9,9] add_col_to_csv('input.csv','output.csv',new_list1)
解决方案
一、优化csv模块直接修改原文件
你当前的代码是生成新文件,要直接修改原文件的话,得注意CSV是行优先存储的,直接在原文件上读写会覆盖内容,所以安全的做法要么是先逐行处理后覆盖写入,要么用临时文件中转再替换原文件(后者更稳妥,避免中途出错丢失数据)。
方式1:逐行读取+覆盖写入(适合文件不是极端大的场景)
import csv def append_col_to_original(csv_path, new_col_data): # 先读取所有行并追加新列数据 rows = [] with open(csv_path, 'r', newline='') as f: reader = csv.reader(f) for idx, row in enumerate(reader): if idx < len(new_col_data): row.append(new_col_data[idx]) rows.append(row) # 覆盖写回原文件 with open(csv_path, 'w', newline='') as f: writer = csv.writer(f) writer.writerows(rows) # 测试调用 new_list1 = ['new_col',4,4,5,5,9,9,9] append_col_to_original('input.csv', new_list1)
方式2:临时文件中转(超大文件首选,更安全)
如果文件大到无法一次性读进内存,就用临时文件逐行处理,完成后替换原文件:
import csv import os import shutil def append_col_safely(csv_path, new_col_data): temp_file = f"{csv_path}.tmp" try: with open(csv_path, 'r', newline='') as read_f, \ open(temp_file, 'w', newline='') as write_f: reader = csv.reader(read_f) writer = csv.writer(write_f) for idx, row in enumerate(reader): if idx < len(new_col_data): row.append(new_col_data[idx]) writer.writerow(row) # 替换原文件 shutil.move(temp_file, csv_path) except Exception as e: # 出错则删除临时文件,避免残留 if os.path.exists(temp_file): os.remove(temp_file) raise e # 测试调用 new_list1 = ['new_col',4,4,5,5,9,9,9] append_col_safely('input.csv', new_list1)
二、用pandas实现列追加的局限性
先明确:pandas的to_csv使用mode='a'是在文件末尾追加行,而非追加列——因为CSV的结构是一行一行存储的,要添加列必须修改每一行的内容,而不是在文件末尾新增行。
如果非要用pandas处理,只能逐块读取原文件,处理后写入临时文件,最后替换原文件,思路和csv模块一致,但pandas的块处理仍会占用一定内存:
import pandas as pd import shutil import os def append_col_with_pandas(csv_path, new_col_data): temp_file = f"{csv_path}.tmp" chunk_size = 1000 # 根据自身内存情况调整块大小 header_written = False # 逐块读取并处理 for chunk in pd.read_csv(csv_path, chunksize=chunk_size): # 给当前块添加新列,注意索引对齐 chunk['new_col'] = new_col_data[chunk.index.start : chunk.index.stop] # 写入临时文件,第一块写表头,后续块不写 chunk.to_csv(temp_file, mode='a', header=not header_written, index=False) header_written = True # 替换原文件 shutil.move(temp_file, csv_path) # 测试调用 new_list1 = ['new_col',4,4,5,5,9,9,9] append_col_with_pandas('input.csv', new_list1)
注意事项
- pandas处理大文件时,
chunksize要调整合适:太小会增加IO次数,太大会占用过多内存。 - 无论用哪种方法,CSV的结构决定了无法直接在原文件上修改每一行来追加列,必须使用临时文件或者先读再写的方式。
内容的提问来源于stack exchange,提问作者GreatShark
相关产品推荐
相关产品推荐

