In breve: non è possibile evitare 2 copie utilizzando StringIO.
Alcune ipotesi:
- Stai usando cStringIO, altrimenti sarebbe sciocco per ottimizzare questo molto.
- È la velocità e non l'efficienza della memoria che stai cercando. In caso contrario, vedere la soluzione di Jakob Bowyer o utilizzare una variante utilizzando
file.read(SOME_BYTE_COUNT)
se il file è binario.
- Lo hai già affermato nei commenti, ma per completezza: vuoi veramente modificare i contenuti, non solo visualizzarli.
Risposta lunga: Dal momento che le stringhe di Python sono immutabili e il buffer StringIO non è, una copia dovrà essere fatta prima o poi; altrimenti cambierai un oggetto immutabile! Per quello che vuoi essere possibile, l'oggetto StringIO dovrebbe avere un metodo dedicato che legge direttamente da un oggetto file dato come argomento. Non esiste un tale metodo.
Fuori da di StringIO, esistono soluzioni che evitano la copia aggiuntiva. Fuori della parte superiore della mia testa, questo leggerà un file direttamente in un array di byte modificabile, non copia extra:
import numpy as np
a = np.fromfile("filename.ext", dtype="uint8")
Può essere ingombrante con cui lavorare, a seconda dell'uso che si intende, dal momento che è una serie di valori da 0 a 255, non una matrice di caratteri. Ma è funzionalmente equivalente a un oggetto StringIO, e l'utilizzo di np.fromstring
, np.tostring
, np.tofile
e la notazione dell'affettatura dovrebbe portarti dove vuoi. Potrebbe anche essere necessario np.insert
, np.delete
e np.append
.
Sono sicuro che ci sono altri moduli che faranno cose simili.
timeit:
Quanto tutto questo davvero questione? Bene vediamo. Ho creato un file da 100 MB, largefile.bin
. Quindi leggo il file usando entrambi i metodi e cambio il primo byte.
$ python -m timeit -s "import numpy as np" "a = np.fromfile('largefile.bin', 'uint8'); a[0] = 1"
10 loops, best of 3: 132 msec per loop
$ python -m timeit -s "from cStringIO import StringIO" "a = StringIO(); a.write(open('largefile.bin').read()); a.seek(0); a.write('1')"
10 loops, best of 3: 203 msec per loop
Quindi nel mio caso, l'uso di StringIO è del 50% più lento rispetto all'uso di numpy.
Infine, per il confronto, la modifica del file direttamente:
$ python -m timeit "a = open('largefile.bin', 'r+b'); a.seek(0); a.write('1')"
10000 loops, best of 3: 29.5 usec per loop
Quindi, è quasi 4500 volte più veloce. Ovviamente, è estremamente dipendente da ciò che farai con il file. La modifica del primo byte è difficilmente rappresentativa. Ma usando questo metodo, hai un vantaggio sugli altri due, e dato che la maggior parte dei SO ha un buon buffering dei dischi, la velocità potrebbe essere molto buona.
(Se non ti è permesso modificare il file e quindi vuoi evitare il costo di fare una copia funzionante, ci sono un paio di modi possibili per aumentare la velocità. Se puoi scegliere il filesystem, Btrfs ha un copy-on-write operazione di copia di file - rendendo l'atto di prendere una copia di un file praticamente istantaneo.Per lo stesso effetto si può ottenere usando uno snapshot LVM di qualsiasi filesystem.)
Cosa hai intenzione di fare con 'stream'? Leggilo?? –
Stai usando Python 2.xo 3.x? –
@JohnMachin: Voglio leggerlo e modificarlo anch'io. La domanda è generale su Python, se c'è differenza tra 2.xe 3.x per favore diciamo – zaharpopov