2012-01-20 9 views
5

Suponga que hay un archivo test.txt que contiene una cadena 'test'.Basura en archivo después de truncado (0) en Python

Ahora, consideremos el siguiente código Python:

f = open('test', 'r+') 
f.read() 
f.truncate(0) 
f.write('passed') 
f.flush(); 

Ahora espero test.txt para contener 'passed' ahora, sin embargo, hay, además, son algunos símbolos extraños!

Actualización: flush after truncate no ayuda.

+1

Por lo que puedo decir, ejecutar 'truncate (0)' simplemente establece el tamaño del archivo en 0 bytes y mueve el puntero del archivo al inicio del búfer. Cuando escribe en la secuencia antes de la descarga, el estado del búfer no está definido. Cuando descarga, pueden aparecer datos basura de ese búfer. La regla general que aplicaría es que debe enjuagar cada vez que intente * eliminar * cualquier cosa, o cuando deba asegurarse de que el archivo se encuentre en un estado particular antes de continuar. – Polynomial

+0

¿qué hay de cerrar el archivo? – joaquin

+0

@El lavado polinómico no funciona, me equivoqué ... – Beginner

Respuesta

4

Esto es porque truncate no cambia la posición de la secuencia.

Cuando read() el archivo, mueve la posición hasta el final. Entonces write sucesivos escribirán en el archivo desde esa posición. Sin embargo, cuando llama al flush(), parece que no solo intenta escribir el búfer en el archivo, sino que también realiza una comprobación de errores y corrige la posición actual del archivo. Cuando se llama al Flush() después del truncate(0), no escribe nada (el búfer está vacío), luego verifica el tamaño del archivo y coloca la posición en el primer lugar aplicable (que es 0).

ACTUALIZACIÓN

función de archivo de Python no son sólo las envolturas alrededor de los equivalentes de la biblioteca estándar de C, pero sabiendo las funciones de C ayuda a saber lo que está sucediendo con mayor precisión.

Desde el ftruncate man page:

El valor del puntero buscar no se modifica por una llamada a ftruncate().

Desde el fflush man page:

Si los puntos de flujo a un flujo de entrada o un canal de actualización en el que la operación más reciente fue de entrada, esa corriente se vacía si es reubicable y no está ya al final -de-archivo. La descarga de una secuencia de entrada descarta cualquier entrada almacenada en el búfer y ajusta el puntero del archivo de modo que la siguiente operación de entrada acceda al byte después de la última lectura.

Esto significa que si pone flush antes de truncate no tiene ningún efecto. Lo revisé y fue así.

Pero para poner flush después truncate:

Si los puntos de flujo para un flujo de salida o un canal de actualización en el que la operación más reciente no era de entrada, fflush() hace que los datos no guardados de esa corriente sea escrito en el archivo, y los campos st_ctime y st_mtime del archivo subyacente están marcados para su actualización.

La página man no menciona el puntero de búsqueda al explicar flujos de salida con la última operación sin entrada. (Aquí la última operación es truncate)

ACTUALIZACIÓN 2

he encontrado algo en el código fuente de Python: Python-3.2.2\Modules\_io\fileio.c:837

#ifdef HAVE_FTRUNCATE 
static PyObject * 
fileio_truncate(fileio *self, PyObject *args) 
{ 
    PyObject *posobj = NULL; /* the new size wanted by the user */ 
#ifndef MS_WINDOWS 
    Py_off_t pos; 
#endif 

... 

#ifdef MS_WINDOWS 
    /* MS _chsize doesn't work if newsize doesn't fit in 32 bits, 
     so don't even try using it. */ 
    { 
     PyObject *oldposobj, *tempposobj; 
     HANDLE hFile; 

////// THIS LINE ////////////////////////////////////////////////////////////// 
     /* we save the file pointer position */ 
     oldposobj = portable_lseek(fd, NULL, 1); 
     if (oldposobj == NULL) { 
      Py_DECREF(posobj); 
      return NULL; 
     } 

     /* we then move to the truncation position */ 
     ... 

     /* Truncate. Note that this may grow the file! */ 
     ... 

////// AND THIS LINE ////////////////////////////////////////////////////////// 
     /* we restore the file pointer position in any case */ 
     tempposobj = portable_lseek(fd, oldposobj, 0); 
     Py_DECREF(oldposobj); 
     if (tempposobj == NULL) { 
      Py_DECREF(posobj); 
      return NULL; 
     } 
     Py_DECREF(tempposobj); 
    } 
#else 

... 

#endif /* HAVE_FTRUNCATE */ 

mirada a las dos líneas que he indicado (///// This Line /////). Si su plataforma es Windows, está guardando la posición y devolviéndola después del truncado.

Para mi sorpresa, la mayoría de las funciones flush dentro de las funciones de Python 3.2.2 o no hicieron nada o no llamaron a la función C fflush en absoluto. La parte truncada 3.2.2 también estaba muy indocumentada. Sin embargo, encontré algo interesante en las fuentes de Python 2.7.2. En primer lugar, me encontré con esto en Python-2.7.2\Objects\fileobject.c:812 en truncate aplicación:

/* Get current file position. If the file happens to be open for 
* update and the last operation was an input operation, C doesn't 
* define what the later fflush() will do, but we promise truncate() 
* won't change the current position (and fflush() *does* change it 
* then at least on Windows). The easiest thing is to capture 
* current pos now and seek back to it at the end. 
*/ 

Entonces, para resumir todo, creo que esto es una cosa totalmente dependientes de la plataforma. Comprobé el Python 3.2.2 predeterminado para Windows x64 y obtuve los mismos resultados que tú. No sé lo que sucede en * nixes.

+0

Vea mi actualización, pero creo que está en el camino correcto. Probablemente debería buscar cero adicionalmente. - ¡Sí, buscar 0 justo después de truncar ayuda! Entonces, ¿cuál es el verdadero propósito de truncar? – Beginner

+0

Mi sistema operativo es Linux, por lo que sospecho que el mismo comportamiento en otros sistemas compatibles con POSIX. – Beginner

-1

Depende. Si desea mantener el archivo abierto y acceder a él sin cerrarlo, el vaciado forzará la escritura en el archivo. Si cierras el archivo inmediatamente después de tirarlo, no, no lo necesitas porque cerrará para ti. Eso es lo que entiendo de docs

+1

Quiero borrar el archivo ... y no, no quiero volver a abrirlo. – Beginner

1

Truncar no cambia la posición del archivo.

Tenga en cuenta también que incluso si el archivo se abre en lectura + escritura no puede simplemente cambiar entre los dos tipos de operación (por ejemplo, se requiere una operación de búsqueda para cambiar de lectura a escritura o viceversa).

0

espero que el siguiente es el código que significa que escribir:

open('test.txt').read() 
open('test.txt', 'w').write('passed') 
0

Sí, es cierto que truncate() no se mueve de la posición, pero dicho esto, es simple como la muerte:

f.read() 
f.seek(0) 
f.truncate(0) 
f.close() 

esto funciona perfectamente;)

Cuestiones relacionadas