2016-02-25 2 views
1

Я раскалываю очень большой csv с помощью этой программы python, основанной на втором столбце «ParentID». Недавно я обновился до «a» вместо «w» из-за большого количества файлов и предела процесса. При этом мои заголовки писали каждый раз, а не только в первый раз в каждом файле.Python not writing заголовки

Я обновил добавить «write_header = истина» и «write_header = ложь», но теперь он только писать заголовок на первый файл ... У меня есть более 29000 файлов

#!/usr/bin/env python3 
import binascii 
import csv 
import os.path 
import sys 
from tkinter.filedialog import askopenfilename, askdirectory 
from tkinter.simpledialog import askinteger 

def split_csv_file(f, dst_dir, keyfunc): 
    csv_reader = csv.reader(f) 
    header = next(csv_reader) 
    write_header = True 
    csv_writers = {} 
    for row in csv_reader: 
     k = keyfunc(row) 
     with open(os.path.join(dst_dir, k), mode='a', newline='') as output: 
      writer = csv.writer(output) 
      while write_header: 
       writer.writerow(header) 
       write_header = False 
      csv_writers[k] = writer 
      csv_writers[k].writerow(row[0:1]) 

def get_args_from_cli(): 
    input_filename = sys.argv[1] 
    column = int(sys.argv[2]) 
    dst_dir = sys.argv[3] 
    return (input_filename, column, dst_dir) 

def get_args_from_gui(): 
    input_filename = askopenfilename(
     filetypes=(('TXT','.txt'),('CSV', '.csv')), 
     title='Select CSV Input File') 
    column = askinteger('Choose Table Column', 'Table column') 
    dst_dir = askdirectory(title='Select Destination Directory') 
    return (input_filename, column, dst_dir) 

if __name__ == '__main__': 
    if len(sys.argv) == 1: 
     input_filename, column, dst_dir = get_args_from_gui() 
    elif len(sys.argv) == 4: 
     input_filename, column, dst_dir = get_args_from_cli() 
    else: 
     raise Exception("Invalid number of arguments") 
    with open(input_filename, mode='r', newline='') as f: 
     split_csv_file(f, dst_dir, lambda r: r[column-1]+'.txt') 
     # if the column has funky values resulting in invalid filenames 
     # replace the line from above with: 
     # split_csv_file(f, dst_dir, lambda r: binascii.b2a_hex(r[column-1].encode('utf-8')).decode('utf-8')+'.csv') 

Вот пример файла, разделяемого ..

<option value=''>Choose SubGroup</option>, ParentID 
<option value='/1990-Accord-DX-Glass-s/37918.htm'>Glass</option>,Accord1990DX422F22A1BodyHardwareBackGlass 
<option value='/1990-Accord-DX-Glass-s/37919.htm'>Glass</option>,Accord1990DX422F22A1BodyHardwareBackGlass 
<option value='/1990-Accord-DX-Reveal-Moldings-s/69090.htm'>Reveal Moldings</option>,Accord1990DX422F22A1BodyHardwareBackGlass 
<option value='/1990-Accord-DX-Reveal-Moldings-s/69091.htm'>Reveal Moldings</option>,Accord1990DX422F22A1BodyHardwareBackGlass 
<option value='/1990-Accord-DX-Center-s/10331.htm'>Center</option>,Accord1990DX422F22A1BodyHardwareConsole 
<option value='/1990-Accord-DX-Cowl-s/16006.htm'>Cowl</option>,Accord1990DX422F22A1BodyHardwareCowl 
<option value='/1990-Accord-DX-Exterior-Trim-s/26889.htm'>Exterior Trim</option>,Accord1990DX422F22A1BodyHardwareFender 
<option value='/1990-Accord-DX-Exterior-Trim-s/26890.htm'>Exterior Trim</option>,Accord1990DX422F22A1BodyHardwareFender 

Как я могу получить заголовок, чтобы писать ТОЛЬКО один раз в каждом выходном файле?

ответ

2

Вы устанавливаете write_header ложным при первом вводе заголовка. Таким образом, только первый файл, который вы открываете, получает этот заголовок.

Track какие файлы заголовка установлены в наборе:

def split_csv_file(f, dst_dir, keyfunc): 
    csv_reader = csv.reader(f) 
    header = next(csv_reader) 
    header_written = set() 
    for row in csv_reader: 
     k = keyfunc(row) 
     with open(os.path.join(dst_dir, k), mode='a', newline='') as output: 
      writer = csv.writer(output) 
      if k not in header_written: 
       writer.writerow(header) 
       header_written.add(k) 
     writer.writerow(row[0:1]) 

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

+0

Это имеет смысл .. однако я новичок в python, поэтому мое понимание немного неясно, поэтому я просто попробовал ваш код и получил эту ошибку: Traceback (последний последний звонок последний): Файл «», строка 14, в split_csv_file ValueError: операция ввода-вывода в закрытом файле. Во время обработки вышеуказанного исключения, другое исключение произошло: Traceback (самый последний вызов последнего): Файл "", строка 9, в Файл "", строки 17, в split_csv_file AttributeError: «_csv объект .writer 'не имеет атрибута' close ' >>> –

+0

Ах, да; Я допустил две ошибки: я оставил инструкцию 'with' на месте и забыл хранить файл отдельно. Поправим в одно мгновение. –

+0

Я вижу ваше редактирование. Спасибо. Но это возвращает меня в начале. Я получаю ту же ошибку «Слишком много открытых файлов», поэтому я переключился на «с открытыми», есть способ запустить ее таким образом и закрыть закрытие файла и снова открыть, если для этого txt-файла появится другой экземпляр. Кажется, он делает именно то, что мне нужно. –