Tengo un pequeño programa de ejemplo escrito en C. Tengo un main que llama a una función writeFile que escribe algunos números en un archivo binario. Luego llamo overwrite para reemplazar 0 con 1 y finalmente imprimo el resultado.
Este es el código:
#include <stdio.h> /* Print the content of the file */ void printFile(){ printf("Read test.dat:\n"); int r; FILE* fp = fopen("test.dat", "rb+"); if(fp) { while(fread(&r,sizeof(int),1,fp)){ printf("%d\n", r); } } fclose(fp); } /* Replace 0 with 1 */ void overwrite(){ int r; FILE *fp = fopen("test.dat", "rb+"); if (fp) { int i=0; while (i < 4 && fread(&r, sizeof(int), 1, fp)) { i++; if (r == 0) { r = 1; fseek(fp,-sizeof(int),SEEK_CUR); fwrite(&r,sizeof(int),1,fp); } } } fclose(fp); } /* Create original file */ void writeFile() { int b, b1, b2, b3, b4; b = 3; b1 = 2; b2 = 0; b3 = 4; FILE *fp = fopen("test.dat", "wb"); if (fp) { fwrite(&b, sizeof(int), 1, fp); fwrite(&b1, sizeof(int), 1, fp); fwrite(&b2, sizeof(int), 1, fp); fwrite(&b3, sizeof(int), 1, fp); } fclose(fp); } int main() { writeFile(); printf("---------BEFORE--------\n"); printFile(); printf("-----------------------\n"); printf("Overwriting...\n"); overwrite(); printf("---------AFTER---------\n"); printFile(); return 0; }Este código funciona con Linux, pero cuando ejecuto el mismo código en Windows, el resultado es este:
---------BEFORE-------- Read test.dat: 3 2 0 4 ----------------------- Overwriting... ---------AFTER--------- Read test.dat: 3 2 1 2No solo el 0 fue reemplazado por 1, sino que también cambió el último número. ¿Alguien puede ayudarme a entender por qué sucede esto?
Otro problema es que en la overwrite debo usar i para parar el while porque sin i<4 obtengo un bucle infinito (solo con Windows).
Probé este código en Windows 8.1 compilado con gcc 4.8.1 (de MinGW). En mi máquina Linux probé el código con gcc 5.1.1.
Gracias a todos,
Es porque necesita fflush() después de fwrite() , ya que no debe llamar a fread() después de llamar a fwrite() sin una llamada intermedia a fflush() ,
Esta es la sección de la norma que es relevante en este caso
7.21.5.3 La función
fopen
- Cuando se abre un archivo con el modo de actualización (
'+'como el segundo o tercer carácter en la lista anterior de valores de argumento de modo), tanto la entrada como la salida se pueden realizar en el flujo asociado. Sin embargo, la salida no debe ser seguida directamente por una entrada sin una llamada intermedia a la funciónfflusho a una función de posicionamiento de archivos (fseek,fsetposorewind), y la entrada no debe ser seguida directamente por una salida sin una llamada intermedia a un posicionamiento de archivos. función, a menos que la operación de entrada encuentre el final del archivo. Abrir (o crear) un archivo de texto con el modo de actualización puede abrir (o crear) un flujo binario en algunas implementaciones.
Es extraño que esta sección esté dentro de la función fopen() ya que involucra fread() y fwrite() , que es donde estaba buscando una respuesta.
También puede ver que mi respuesta anterior funcionó, pero no por la razón que indiqué en ella, sino que la explicación se encuentra en el párrafo anterior.
Estados de MSDN para Stream I/O :
La entrada puede seguir a la salida directamente solo con una llamada intermedia a
fflusho a una función de posicionamiento de archivos (fseek,fsetposorewind). La salida puede seguir a la entrada sin una llamada intermedia a una función de posicionamiento de archivos si la operación de entrada encuentra el final del archivo.
Entonces tendrías que llamar a fflush() después de llamar a fwrite:
void overwrite() { FILE *fp = fopen("test.dat", "rb+"); if (fp) { int r; while (fread(&r, sizeof(int), 1, fp) == 1) { if (r == 0) { r = 1; fseek(fp,-sizeof(int),SEEK_CUR); fwrite(&r,sizeof(int),1,fp); fflush(fp); /* Flush here */ } } fclose(fp); /* Also: call fclose() only when fopen() succeeded */ } }