Nel codice corrente, stai leggendo l'intero file in memoria in una sola volta. Dal momento che sono file da 500 Mb, ciò significa stringhe da 500 Mb. E poi ne fai ripetute sostituzioni, il che significa che Python deve creare una nuova stringa da 500 Mb con la prima sostituzione, quindi distruggere la prima stringa, quindi creare una seconda stringa da 500 Mb per la seconda sostituzione, quindi distruggere la seconda stringa, eccetera, per ogni sostituzione. Questo risulta essere un bel po 'di copia dei dati avanti e indietro, per non parlare dell'uso di molta memoria.
Se si sa che le sostituzioni saranno sempre contenute in una riga, è possibile leggere il file riga per riga ripetendo su di esso. Python bufferizzerà la lettura, il che significa che sarà abbastanza ottimizzato. Dovresti aprire un nuovo file, con un nuovo nome, per scrivere contemporaneamente il nuovo file. Eseguire a turno la sostituzione su ciascuna riga e scriverla immediatamente.In questo modo si riduce notevolmente la quantità di memoria utilizzata e la quantità di memoria copiati avanti e indietro come si fa le sostituzioni:
for file in files:
fname = os.path.join(dir, file)
inFile = codecs.open(fname, "r", "utf-8")
outFile = codecs.open(fname + ".new", "w", "utf-8")
for line in inFile:
newline = do_replacements_on(line)
outFile.write(newline)
inFile.close()
outFile.close()
os.rename(fname + ".new", fname)
Se non si può essere certi se sarò sempre in una riga le cose diventano un po 'più difficili; dovresti leggere i blocchi manualmente, usando inFile.read(blocksize)
, e tenere traccia attentamente se ci potrebbe essere una corrispondenza parziale alla fine del blocco. Non è facile da fare, ma in genere vale comunque la pena di evitare le stringhe da 500 Mb.
Un altro grande miglioramento sarebbe se si potesse fare le sostituzioni in un colpo solo, piuttosto che provare un intero gruppo di sostituzioni in ordine. Ci sono diversi modi per farlo, ma quello che si adatta meglio dipende interamente da ciò che stai sostituendo e con cosa. Per tradurre singoli caratteri in qualcos'altro, il metodo translate
di oggetti Unicode può essere conveniente. Si passa una mappatura dict codepoints Unicode (come numeri interi) per le stringhe Unicode:
>>> u"\xff and \ubd23".translate({0xff: u"255", 0xbd23: u"something else"})
u'255 and something else'
Per sostituzione di sottostringhe (e non solo singoli caratteri), è possibile utilizzare il modulo re
. La funzione re.sub
(e il metodo di espressioni regolari compilate sub
) può prendere un callable (una funzione) come primo argomento, che verrà poi chiamata per ogni partita:
>>> import re
>>> d = {u'spam': u'spam, ham, spam and eggs', u'eggs': u'saussages'}
>>> p = re.compile("|".join(re.escape(k) for k in d))
>>> def repl(m):
... return d[m.group(0)]
...
>>> p.sub(repl, u"spam, vikings, eggs and vikings")
u'spam, ham, spam and eggs, vikings, saussages and vikings'
È la convenzione di Python per denominare le variabili di istanza con lettere minuscole. Sostituirei anche la parola 'Dict' con qualcosa di diverso dal tipo, per evitare confusione futura. –
Le chiavi del dizionario sono costituite da esattamente 1 carattere cinese ciascuna o sono possibili più caratteri per chiave? Perché vuoi sostituire i caratteri cinesi con numeri interi? –
@John: Ho altri 35 file con queste informazioni già codificate con numeri interi, e farò la mia analisi su Stata, che non legge l'unicode. Ho bisogno di leggere più caratteri alla volta, non solo 1. – rallen