En resumen: no puede evitar 2 copias con StringIO.
Algunos supuestos:
- Estás usando cStringIO, de lo contrario sería tonto para optimizar tanto.
- Es la velocidad y no la eficiencia de la memoria lo que buscas. De lo contrario, consulte la solución de Jakob Bowyer, o use una variante usando
file.read(SOME_BYTE_COUNT)
si su archivo es binario.
- Ya lo ha expresado en los comentarios, pero para completarlo: quiere editar realmente los contenidos, no solo verlos.
Respuesta larga: Como las cadenas de Python son inmutables y la memoria intermedia StringIO no es, una copia tendrá que ser realizado antes o después; de lo contrario estarías alterando un objeto inmutable! Para lo que quiere ser posible, el objeto StringIO necesitaría tener un método dedicado que lea directamente de un objeto de archivo dado como argumento. No hay tal método.
Fuera de de StringIO, hay soluciones que evitan la copia adicional. De la parte superior de mi cabeza, esto va a leer un archivo directamente en una matriz de bytes modificable, sin copia extra:
import numpy as np
a = np.fromfile("filename.ext", dtype="uint8")
Puede ser engorroso para trabajar, dependiendo del uso que usted tiene la intención, ya que es un conjunto de valores de 0 a 255, no una matriz de caracteres. Pero es funcionalmente equivalente a un objeto StringIO, y usando np.fromstring
, np.tostring
, np.tofile
y la notación de corte debería llevarlo a donde lo desee. Es posible que también necesite np.insert
, np.delete
y np.append
.
Estoy seguro de que hay otros módulos que harán cosas similares.
TimeIt:
¿Cuánto cuesta todo esto realmente importa ? Bien, veamos. He hecho un archivo de 100MB, largefile.bin
. Luego leo en el archivo usando ambos métodos y cambio el primer 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
Así que, en mi caso, utilizar StringIO es un 50% más lento que usar numpy.
Por último, para la comparación, editar el archivo directamente:
$ 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
Por lo tanto, es casi 4.500 veces más rápido. Por supuesto, es extremadamente dependiente de lo que vas a hacer con el archivo. Alterar el primer byte es poco representativo. Pero al usar este método, tienes una ventaja sobre los otros dos, y como la mayoría de los SO tienen un buen almacenamiento de memoria en los discos, la velocidad también puede ser muy buena.
(Si no puede editar el archivo y quiere evitar el costo de hacer una copia de trabajo, hay un par de maneras posibles de aumentar la velocidad. Si puede elegir el sistema de archivos, Btrfs tiene una copy-on-write operación de copia de archivos: tomar el acto de tomar una copia de un archivo prácticamente al instante. Se puede lograr el mismo efecto usando una instantánea LVM de cualquier sistema de archivos)
¿Qué vas a hacer con 'stream'? Léelo? –
¿Está utilizando Python 2.xo 3.x? –
@JohnMachin: Quiero leer y modificarlo también. La pregunta es general sobre Python, si hay una diferencia entre 2.x y 3.x, por favor diga – zaharpopov