2010-12-17 13 views
6

Supponiamo di avere un VPS Ubuntu da 10 GB negli Stati Uniti (e in alcuni altri dove vivo), e ho un file di testo da 9 GB sul disco rigido . Ho 512 MB di RAM e circa la stessa quantità di scambio.Come rimuovere le linee da un file grande in Python, in un ambiente limitato

Dato che non riesco ad aggiungere altro spazio su disco fisso e non posso spostare il file da qualche altra parte per elaborare, esiste un metodo efficace per rimuovere alcune righe dal file usando Python (preferibilmente, ma qualsiasi altra lingua sarà accettabile) ?

risposta

3

ne dici di questo? Modifica il file sul posto. Ho provato su alcuni piccoli file di testo (in Python 2.6.1), ma non sono sicuro di quanto bene si esibirà il massiccio file a causa di tutto il saltare, ma ancora ...

I' Ho usato un ciclo while indefinito con un controllo EOF manuale, perché for line in f: non ha funzionato correttamente (presumibilmente tutti i salti intorno rovinano la normale iterazione). Potrebbe esserci un modo migliore per verificarlo, ma sono relativamente nuovo a Python, quindi qualcuno mi faccia sapere se c'è.

Inoltre, è necessario definire la funzione isRequired(line).

writeLoc = 0 
readLoc = 0 
with open("filename" , "r+") as f: 
    while True: 
     line = f.readline() 

     #manual EOF check; not sure of the correct 
     #Python way to do this manually... 
     if line == "": 
      break 

     #save how far we've read 
     readLoc = f.tell() 

     #if we need this line write it and 
     #update the write location 
     if isRequired(line): 
      f.seek(writeLoc) 
      f.write(line) 
      writeLoc = f.tell() 
      f.seek(readLoc) 

    #finally, chop off the rest of file that's no longer needed 
    f.truncate(writeLoc) 
+0

+1: quasi esattamente la mia soluzione, ma con tutti i dettagli non chiari compilati e testati. –

+1

Ottima soluzione. –

+0

Grazie per il suggerimento, sono un po 'preoccupato che se qualcosa di sbagliato è successo durante questo processo, il mio file non sarebbe nello stato originale? Dato il fatto che i numeri di riga effettivamente contano nella funzione isRequired (linea). Sono consapevole del fatto che posso registrare/scrivere su un file per "ricordare" ciò che è stato cambiato e continuare dopo, ma vorrei vedere se c'è un modo senza sforzo per raggiungere questo obiettivo. –

0

Basta leggere e scrivere sequenzialmente nei file.

f.readlines() restituisce una lista contenente tutte le righe di dati in file. Se viene data una dimensione parametro opzionale , legge che molti byte dal file e abbastanza altro da completano una linea e restituiscono le linee da quello. Viene spesso utilizzato per consentire la lettura efficiente di di un file di grandi dimensioni tramite le linee , ma senza caricare l'intero file nella memoria. Vengono restituite solo le righe .

Source

+0

Scrivi a dove? Non c'è abbastanza spazio. – khachik

+0

Dipende dall'architettura/file system, immagino ... ma direi che non è possibile modificare un file in quel senso, è necessario scriverlo di nuovo. – phant0m

0

elaborare il file ottenendo 10/20 o più MB di blocchi. Questo sarebbe il modo più veloce.

Un altro modo per fare ciò è eseguire lo streaming di questo file e filtrarlo utilizzando ad esempio AWK.

esempio di codice pseudo:

file = open(rw) 
linesCnt=50 
newReadOffset=0 
tmpWrtOffset=0 
rule=1 
processFile() 
{ 
    while(rule) 
    { 
     (lines,newoffset)=getLines(file, newReadOffset) 
     if lines: 
      [x for line in lines if line==cool: line] 
      tmpWrtOffset = writeBackToFile(file, x, tmpWrtOffset) #should return new offset to write for the next time 
     else: 
      rule=0 
    } 
} 

Per ridimensionare file alla l'uso finale truncate(size=None)

+0

'-1 odiatore', per favore, spiega perché pensi che sia una merda? – bua

+4

Perché dovresti scrivere pseudocodice per Python? Del resto, perché dovresti scrivere uno pseudocodice che appaia di livello più basso di quello che normalmente fa Python? –

+0

Perché non ho possibilità di controllare è in esecuzione e io non sono un programmatore Python nativo. Questo dovrebbe solo dare un'idea di cosa dovrebbe essere a conoscenza. Quello che il codice finale sarà simile non è il mio problema .... – bua

2

Prova questo:

currentReadPos = 0 
removedLinesLength = 0 
for line in file: 
    currentReadPos = file.tell() 
    if remove(line): 
     removedLinesLength += len(line) 
    else: 
     file.seek(file.tell() - removedLinesLength) 
     file.write(line + "\n") 
     file.flush() 
    file.seek(currentReadPos) 

non ho eseguito questo, ma l'idea è quella di modificare il file in posizione sovrascrivendo le linee che si desidera rimuovere con le linee che si desidera conservare. Non sono sicuro di come la ricerca e la modifica interagiscano con l'iterazione sul file.

+0

+1 per fornire rilevanti informazioni/utili –

1

Aggiornamento:

ho cercato fileinput con inplace creando un file da 1 GB. Quello che mi aspettavo era diverso da quello che era successo. Ho letto la documentazione correttamente questa volta.

filtraggio inplace Opzionale: se l'argomento inplace parola chiave = 1 viene passato a fileinput.input() o al costruttore di FileInput , il file è spostati in un file di backup e standard di uscita è indirizzato al file di input (se esiste già un file con lo stesso nome del file di backup , sarà sostituito automaticamente da ).

da docs/fileinput

Quindi, questo non sembra essere un'opzione ora per voi. Si prega di controllare altre risposte.


Prima Edit:

Se siete alla ricerca di modifica del file inplace, quindi controllare il modulo di Python fileinput - Docs.

io non sono davvero sicuro circa la sua efficacia quando viene utilizzato con un file di 10 GB. Ma, per me, questa sembrava essere l'unica opzione che hai usato con Python.

+0

Grazie, +1 per la fornitura relativa risposta. –

Problemi correlati