Добавить заголовок в CSV без загрузки CSV

Есть ли способ добавить строку заголовка в CSV без загрузки CSV в память в python? У меня есть CSV на 18 ГБ, я хочу добавить заголовок, и все методы, которые я видел, требуют загрузки CSV в память, что явно неосуществимо.

Ответ 1

Просто используйте тот факт, что модуль csv выполняет итерацию по строкам, поэтому он никогда не загружает весь файл в память

import csv

with open("huge_csv.csv") as fr, open("huge_output.csv","w",newline='') as fw:
    cr = csv.reader(fr)
    cw = csv.writer(fw)
    cw.writerow(["title1","title2","title3"])
    cw.writerows(cr)

используя writerows, обеспечивают очень хорошую скорость. Здесь хранится память. Все делается по очереди. Поскольку данные правильно обработаны, вы даже можете изменить разделитель и/или цитату в выходном файле.

Ответ 2

Вам нужно будет переписать весь файл. Проще всего не использовать python

echo 'col1, col2, col2,... ' > out.csv
cat in.csv >> out.csv

Решения на основе Python будут работать на гораздо более высоких уровнях и будут намного медленнее. 18GB - это много данных. Лучше работать с функциональностью операционной системы, которая будет самой быстрой.

Ответ 3

Ниже приведено сравнение трех предложенных решений для CSV файла размером 200 МБ с 10 ^ 6 строками и 10 столбцами (n = 50). Соотношение примерно одинаково для больших и меньших файлов (от 10 МБ до 8 ГБ).

cp: shutil: csv_reader 1:10:55

то есть. использование встроенной функции cp примерно в 55 раз быстрее, чем использование модуля Python csv.

Компьютер:

  • обычный жесткий диск
  • Python 3.5.2 64-разрядный
  • Ubuntu 16.04
  • i7-3770

введите описание изображения здесь


import csv
import random
import shutil
import time
import subprocess

rows = 1 * 10**3
cols = 10
repeats = 50

shell_script = '/tmp/csv.sh'
input_csv = '/tmp/temp.csv'
output_csv = '/tmp/huge_output.csv'
col_titles = ['titles_' + str(i) for i in range(cols)]

with open(shell_script, 'w') as f:
    f.write("#!/bin/bash\necho '{0}' > {1}\ncat {2} >> {1}".format(','.join(col_titles), output_csv, input_csv))

with open(shell_script, 'w') as f:
    f.write("echo '{0}' > {1}\ncat {2} >> {1}".format(','.join(col_titles), output_csv, input_csv))
subprocess.call(['chmod', '+x', shell_script])

run_times = dict([
    ('csv_writer', list()),
    ('external', list()),
    ('shutil', list())
])

def random_csv():
    with open(input_csv, 'w') as csvfile:
        csv_writer = csv.writer(csvfile, delimiter=',')
        for i in range(rows):
            csv_writer.writerow([str(random.random()) for i in range(cols)])
    with open(output_csv, 'w'):
        pass

for r in range(repeats):
    random_csv()
    #http://stackoverflow.com/a/41982368/2776376
    start_time = time.time()
    with open(input_csv) as fr, open(output_csv, "w", newline='') as fw:
        cr = csv.reader(fr)
        cw = csv.writer(fw)
        cw.writerow(col_titles)
        cw.writerows(cr)
    run_times['csv_writer'].append(time.time() - start_time)

    random_csv()
    #http://stackoverflow.com/a/41982383/2776376
    start_time = time.time()
    subprocess.call(['bash', shell_script])
    run_times['external'].append(time.time() - start_time)

    random_csv()
    #http://stackoverflow.com/a/41982383/2776376
    start_time = time.time()
    with open('header.txt', 'w') as header_file:
        header_file.write(','.join(col_titles))

    with open(output_csv, 'w') as new_file:
        with open('header.txt', 'r') as header_file, open(input_csv, 'r') as main_file:
            shutil.copyfileobj(header_file, new_file)
            shutil.copyfileobj(main_file, new_file)
    run_times['shutil'].append(time.time() - start_time)

    print('#'*20)
    for key in run_times:
        print('{0}: {1:.2f} seconds'.format(key, run_times[key][-1]))

print('#'*20)
print('Averages')
for key in run_times:
    print('{0}: {1:.2f} seconds'.format(key, sum(run_times[key])/len(run_times[key])))

Если вы действительно хотите это сделать в Python, вы можете сначала создать файл заголовка, а затем объединить его со своим вторым файлом через shutil.copyfileobj.

import shutil
with open('header.txt', 'w') as header_file:
    header_file.write('col1;col2;col3')

with open('new_file.csv', 'w') as new_file:
    with open('header.txt', 'r') as header_file, open('main.csv', 'r') as main_file:
        shutil.copyfileobj(header_file, new_file)
        shutil.copyfileobj(main_file, new_file)