2013-03-05 20 views
7

questo è un precedente question in cui per migliorare le prestazioni tempo di una funzione in pitone ho bisogno di trovare un modo efficace per dividere il mio file di testomodo Efficiente di dividere un file di testo di grandi dimensioni in python

ho il seguente testo di file (più di 32 GB) non allineati

.................... 
0 274 593869.99 6734999.96 121.83 1, 
0 273 593869.51 6734999.92 121.57 1, 
0 273 593869.15 6734999.89 121.57 1, 
0 273 593868.79 6734999.86 121.65 1, 
0 272 593868.44 6734999.84 121.65 1, 
0 273 593869.00 6734999.94 124.21 1, 
0 273 593868.68 6734999.92 124.32 1, 
0 274 593868.39 6734999.90 124.44 1, 
0 275 593866.94 6734999.71 121.37 1, 
0 273 593868.73 6734999.99 127.28 1, 
............................. 

la prima e la seconda colonna sono l'ID (es: 0 -273) della posizione x, y, z punto in una griglia.

def point_grid_id(x,y,minx,maxy,distx,disty): 
    """give id (row,col)""" 
    col = int((x - minx)/distx) 
    row = int((maxy - y)/disty) 
    return (row, col) 

il (minx, maxx) è l'origine della mia griglia con dimensioni distx,disty. I numeri delle piastrelle Id sono

tiles_id = [j for j in np.ndindex(ny, nx)] #ny = number of row, nx= number of columns 
from [(0,0),(0,1),(0,2),...,(ny-1,nx-1)] 
n = len(tiles_id) 

ho bisogno di tagliare il file ~ 32 GB in n (= len(tiles_id)) numero di file.

posso farlo senza ordinare ma leggendo n volte il file. Per questo motivo desidero trovare un efficiente metodo di divisione per il file che inizia con il modulo (0,0) (= tiles_id[0]). Dopo di che posso leggere solo una volta i file divisi.

+4

come non usare Python? –

+4

I LOVE Python !! –

+0

Non sei sicuro di quanto sia davvero efficace ottenere con Python per ordinare un file di quelle dimensioni. –

risposta

5

L'ordinamento è difficilmente possibile per un file da 32 GB, non importa se si utilizza Python o uno strumento da riga di comando (sort). I database sembrano troppo potenti, ma possono essere utilizzati. Tuttavia, se non si desidera utilizzare i database, suggerirei semplicemente di dividere il file sorgente nei file usando l'id tile.

Si legge una riga, si crea un nome file da un id di tile e si aggiunge la riga al file. E continua fino al termine del file sorgente. Non sarà troppo veloce, ma almeno ha una complessità di O (N) a differenza dell'ordinamento.

E, naturalmente, è possibile ordinare singoli file e concatenarli. Il principale collo di bottiglia nell'ordinamento di un file da 32 GB dovrebbe essere la memoria, non la CPU.

Ecco, penso:

def temp_file_name(l): 
    id0, id1 = l.split()[:2] 
    return "tile_%s_%s.tmp" % (id0, id1) 

def split_file(name): 
    ofiles = {} 
    try: 
     with open(name) as f: 
      for l in f: 
       if l: 
        fn = temp_file_name(l) 
        if fn not in ofiles: 
         ofiles[fn] = open(fn, 'w') 
        ofiles[fn].write(l) 
    finally: 
     for of in ofiles.itervalues(): 
      of.close() 

split_file('srcdata1.txt') 

Ma se c'è un sacco di piastrelle, oltre il numero di file è possibile aprire, si può farlo:

def split_file(name): 
    with open(name) as f: 
     for l in f: 
      if l: 
       fn = temp_file_name(l) 
       with open(fn, 'a') as of: 
        of.write(l) 

E il il modo più perfezionista è quello di chiudere alcuni file e rimuoverli dal dizionario dopo aver raggiunto un limite sul numero di file aperti.

+0

E quindi è possibile ordinare facilmente i singoli file. –

+0

ma ho bisogno di leggere solo una volta? –

+3

Certo che è possibile. Dovresti usare un ordinamento multi-file e unire, ma è possibile. –

1

Un google veloce mi ha portato a this recipe in codice ActiveState. Non ha dato alcun confronto delle prestazioni, ma sembra fare il lavoro.

In breve, sembra fare ciò che @Ellioh ha suggerito, e tu hai una ricetta pronta e potresti non dover reinventare la ruota.

Problemi correlati