Mezcla read () y write () en archivos Python en Windows

Parece que una write() inmediatamente después de una read() en un archivo abierto con permisos r+ (o r+b ) en Windows no actualiza el archivo.

Supongamos que hay un archivo testfile.txt en el directorio actual con el siguiente contenido:

 This is a test file. 

Ejecuto el siguiente código:

 with open("testfile.txt", "r+b") as fd: print fd.read(4) fd.write("----") 

Espero que el código imprima This y actualice el contenido del archivo a esto:

 This----a test file. 

Esto funciona bien en al menos Linux. Sin embargo, cuando lo ejecuto en Windows, el mensaje se muestra correctamente, pero el archivo no se modifica, es como si se ignorara la write() . Si llamo a tell() en el identificador de archivo, se muestra que la posición se ha actualizado (es 4 antes de write() y 8 después), pero no hay cambios en el archivo.

Sin embargo, si coloco un fd.seek(4) explícito justo antes de la línea de write() , entonces todo funciona como esperaba.

¿Alguien sabe la razón de este comportamiento en Windows?

Para referencia, estoy usando Python 2.7.3 en Windows 7 con una partición NTFS.

EDITAR

En respuesta a los comentarios, probé r+b y rb+ : los documentos oficiales de Python parecen implicar que el primero es canónico.

fd.flush() llamadas a fd.flush() en varios lugares, y colocando una entre la read() y la write() esta manera:

 with open("testfile.txt", "r+b") as fd: print fd.read(4) fd.flush() fd.write("----") 

… produce el siguiente error interesante:

 IOError: [Errno 0] Error 

Editar 2

Indirectamente, la adición de un flush() ayudó porque me llevó a esta publicación que describe un problema similar. Si uno de los comentaristas es correcto, es un error en la biblioteca de Windows C subyacente.

La operación de archivo de Python debe seguir la convención libc ya que se implementa internamente utilizando las funciones IO de C.

Citar la página del manual de fopen o la página de fopen en cplusplus

Para los archivos abiertos para anexar (aquellos que incluyen un signo “+”), en los que se permiten las operaciones de entrada y salida, el flujo debe vaciarse (fflush) o reposicionarse (fseek, fsetpos, rebobinar) entre una operación de escritura seguida de una operación de lectura o una operación de lectura que no alcanzó el final del archivo seguida de una operación de escritura.

Para resumir, si necesita leer un archivo después de escribirlo, debe fflush el búfer y una operación de escritura después de leer debe ir precedida por un fseek , como fd.seek(0, os.SEEK_CUR)

Así que simplemente cambia tu fragmento de código a

 with open("test1.txt", "r+b") as fd: print fd.read(4) fd.seek(0, os.SEEK_CUR) fd.write("----") 

El comportamiento es consistente con cómo se comportaría un progtwig de C similar

 #include  int main() { char buffer[5] = {0}; FILE *fp = fopen("D:\\Temp\\test1.txt","rb+"); fread(buffer, sizeof(char), 4, fp); printf("%s\n", buffer); /*without fseek, file would not be updated*/ fseek(fp, 0, SEEK_CUR); fwrite("----",sizeof(char), 4, fp); fclose(fp); return 0; } 

Parece que esto se debe al comportamiento de las bibliotecas de Windows subyacentes (que personalmente considero que están en error) y no hay nada de malo en Python. Al agregar una llamada al flush() entre lectura y escritura (lo que aparentemente es una buena práctica ) obtuve un IOError con cero errno, que es el mismo problema que se comenta en esta publicación del blog .

De ese post encontré este problema de Python que menciona el problema y dice que la llamada seek() es en realidad la mejor solución, junto con una flush() cada vez que cambias de lectura a escritura.

Todo lo que se tiene en cuenta, parece que la mejor manera de escribir el código anterior para que se ejecute correctamente en Windows es:

 with open("testfile.txt", "r+b") as fd: print fd.read(4) fd.flush() fd.seek(4) fd.write("----") 

Podría ser algo a tener en cuenta para cualquiera que intente escribir un código portátil.

¿Has intentado enrojecer?

 fd.flush() 

depende del sistema operativo, ya que la escritura utiliza el mecanismo de almacenamiento en caché del sistema de archivos

¿Es posible que la implementación interprete mal “r + b”? Afaik “rb +” es para leer y escribir en binario.