2016-09-10 1 views
2

Ich habe eine (sehr groß) CSV-Datei, die etwa wie folgt aussieht:Python: effiziente Möglichkeit, nur ein paar Zeilen in einem csvreader Iterator zu überprüfen?

header1,header2,header3 
name0,rank0,serial0 
name1,rank1,serial1 
name2,rank2,serial2 

ich einige Code geschrieben haben, der die Datei verarbeitet, und schreibt sie aus (mit csvwriter) als solche modifiziert, mit einigen Informationen ich compute bis zum Ende jeder Zeile angefügt:

header1,header2,header3,new_hdr4,new_hdr5 
name0,rank0,serial0,salary0,base0 
name1,rank1,serial1,salary1,base1 
name2,rank2,serial2,salary2,base2 

Was ich versuche Struktur zu tun, ist das Skript, so dass es automatisch erkennt, ob die CSV-Datei, die es liest hat bereits verarbeitet . Wenn es verarbeitet wurde, kann ich später viele teure Berechnungen überspringen. Ich versuche zu verstehen, ob es einen vernünftigen Weg gibt, dies innerhalb der Leserschleife zu tun. I könnte nur die Datei einmal öffnen, genug einlesen, um die Erkennung zu tun, und dann schließen und öffnen Sie es mit einem Flag gesetzt, aber das scheint hackish.

Gibt es eine Möglichkeit, dies im selben Leser zu tun? Die Logik ist so etwas wie:

read first N lines ###(N is small) 
    if (some condition) 
     already_processed = TRUE 
     read_all_csv_without_processing 
    else 
     read_all_csv_WITH_processing 

Ich kann nicht nur den Iterator verwenden, die Leser gibt mir, weil durch die Zeit, die ich genug Zeilen bekommen habe meinen bedingten Scheck zu tun, ich habe keine gute Möglichkeit, um zum Anfang der CSV zurückzukehren. Schließen und Wiedereröffnung es wirklich die eleganteste Art, dies zu tun?

+0

Ihre eigene Lösung ist die beste: Öffnen Sie die Datei, lesen Sie ein paar Zeilen, schließen Sie die Datei und öffnen Sie die Datei erneut. Starten Sie dann eine Schleife mit einem gesetzten Flag, wenn sie verarbeitet wird oder nicht. Es ist überhaupt nicht hackisch, das zu tun. Das Öffnen und Schließen von Dateien ist ziemlich schnell, und als Vorteil werden die Dateidaten beim erneuten Lesen der Datei wahrscheinlich immer noch im Cache der Betriebssystemdatei gespeichert. – dawg

+1

Warum behalten Sie nicht einfach auf, was Sie verarbeitet haben? –

+0

@PadraicCunningham: das ist im Grunde, was ich tue - Ich möchte, dass der Code in der Lage ist zu sagen, ob es eine "verarbeitete" CSV oder eine "rohe" CSV durch das Vorhandensein der neuen Felder liest. * Wenn * ich eine Datei öffne, die bereits ausgeführt wurde, muss ich noch einige interne Datenstrukturen aktualisieren, aber es gibt einen großen Teil der Verarbeitung, die übersprungen werden kann. Ich habe anfangs versucht, die "vollständig verarbeitete" Datenstruktur zu picken, aber es dauerte genauso lange, die Pickle-Datei zu öffnen, als sie aus den Rohdaten neu zu erstellen. (Was ich für merkwürdig hielt, aber ich habe das mehrmals getestet ...) – ljwobker

Antwort

1

Wenn Sie die übliche Python-Methode verwenden, um die Datei zu lesen (with open("file.csv","r") as f: oder gleichwertig), können Sie die Datei lesen, indem Sie f.seek(0) aufrufen.

Hier ist ein Stück Code, der (ich schätze) ein bisschen mehr wie die Art, wie Sie Ihre Datei lesen, aussehen sollte. Es demonstate dass csvfile mit csvfile.seek(0) Reseting auch csvreader zurückgesetzt werden:

with open('so.txt', 'r') as csvfile: 
    csvreader = csv.reader(csvfile, delimiter=',') 
    for row in csvreader: 
     print('Checking if processed') 
     print(', '.join(row)) 
     #if condition: 
     if True: 
      print('File already processed') 
      already_processed = True 
      print('Reseting the file') 
      csvfile.seek(0) 
      for row in csvreader: 
       print(', '.join(row)) 
      break 
1

Ich nehme an, wenn Sie testen wollen nicht nur die ersten Zeilen der Datei können Sie eine einzelne Iterator aus einer Liste erstellen könnte und dann die Fortsetzung des csv-lesers.

Gegeben:

header1,header2,header3 
name0,rank0,serial0 
name1,rank1,serial1 
name2,rank2,serial2 

Sie tun können:

import csv 
from itertools import chain 

with open(fn) as f: 
    reader=csv.reader(f) 
    header=next(reader) 
    N=2 
    p_list=[] 
    for i in range(N): # N is however many you need to set processed flag 
     p_list.append(next(reader)) 
    print("p_list:", p_list) 
    # now use p_list to determine if processed however processed=check(p_list) 

    for row in chain(iter(p_list), reader): # chain creates a single csv reader... 
     # handler processed or not here from the stream of rows... 
     # if not processed: 
     #  process 
     # else: 
     #  handle already processed... 
     # print row just to show csv data is complete: 
     print(row) 

Drucke:

p_list: [['name0', 'rank0', 'serial0'], ['name1', 'rank1', 'serial1']] 
['name0', 'rank0', 'serial0'] 
['name1', 'rank1', 'serial1'] 
['name2', 'rank2', 'serial2'] 
+1

'itertools.islice' kann viel von der Logik ersetzen –

0

denke ich, was Sie versuchen, die ersten Zeilen zu verwenden, zu erreichen, ist zu entscheiden, zwischen der Art der Verarbeitung, dann verwenden Sie diese Zeilen für Ihre read_all_csv_WITH_processing oder read_all_csv_without_processing, während immer noch nicht die volle CSV-Datei im Speicher geladen wird. Um das zu erreichen, dass man die ersten Zeilen in einer Liste laden und verketten, dass mit dem Rest der Datei mit itertools.chain, wie folgt aus:

import itertools 

top_lines = [] 
reader_iterator = csv.reader(fil) 
do_heavy_processing = True 
while True: 
    # Can't use "for line in reader_iterator" directly, otherwise we're 
    # going to close the iterator when going out of the loop after the first 
    # N iterations 
    line = reader_iterator.__next__() 
    top_lines.append(line) 
    if some_condition(line): 
     do_heavy_processing = False 
     break 
    elif not_worth_going_further(line) 
     break 
full_file = itertools.chain(top_lines, reader_iterator) 

if do_heavy_processing: 
    read_all_csv_WITH_processing(full_file) 
else: 
    read_all_csv_without_processing(full_file) 
-1

Ich werde darlegen, was ich einen viel besseren Ansatz in Betracht ziehen. Ich nehme an, dass dies über verschiedene Läufe geschieht.Was Sie tun müssen, ist, die Dateien zwischen den Läufen und nur Prozess gesehen bestehen bleiben, was nicht gesehen worden ist:

import pickle 
import glob 


def process(fle): 
    # read_all_csv_with_processing 

def already_process(fle): 
    # read_all_csv_without_processing 
try: 
    # if it exists, we ran the code previously. 
    with open("seen.pkl", "rb") as f: 
    seen = pickle.load(f) 
except IOError as e: 
    # Else first run, so just create the set. 
    print(e) 
    seen = set() 

for file in glob.iglob("path_where_files_are/*.csv"): 
    # if not seen before, just process 
    if file not in seen: 
     process(file) 
    else: 
     # already processed so just do whatever 
     already_process(file) 
    seen.add(file) 

# persist the set. 
with open("seen.pkl", "w") as f: 
    pickle.dumps(seen, f) 

Auch wenn aus irgendeinem seltsamen Grund, warum Sie irgendwie die gleichen Dateien im gleichen Lauf verarbeiten, alles, was Sie tun müssen, dann wird die gesehene Setzlogik implementiert.

Eine andere Alternative wäre die Verwendung eines eindeutigen Markers in der Datei, die Sie bei der Verarbeitung am Anfang hinzufügen.

# something here 
header1,header2,header3,new_hdr4,new_hdr5 
name0,rank0,serial0,salary0,base0 
name1,rank1,serial1,salary1,base1 
name2,rank2,serial2,salary2,base2 

Dann alles, was Sie verarbeiten müssen, ist die erste Zeile. Auch wenn Sie die ersten n Zeilen aus einer Datei, auch wenn Sie zu start from a certain row, bekommen itertools.islce

Um robust zu sein, möchten Sie vielleicht wickeln Sie Ihren Code in einem Try/finally, falls es Fehler verwenden wollte, so dass Sie dies nicht tun über die gleichen Dateien, die bereits beim nächsten Lauf verarbeitet wurden:

try: 
    for file in glob.iglob("path_where_files_are/*.csv"): 
     # if not seen before, just process 
     if file not in seen: 
      process(file) 
     else: 
      # already processed so just do whatever 
      already_process(file) 
     seen.add(file) 
finally: 
    # persist the set. 
    with open("seen.pkl", "wb") as f: 
     pickle.dump(seen, f) 
Verwandte Themen