Función C para insertar texto en una ubicación particular en el archivo sin sobreescribir el texto existente

He escrito un progtwig que toma un archivo como entrada y cada vez que encuentra una línea con una longitud> 80, agrega \ y \ n a ese archivo para que sea de 80 caracteres de ancho máximo.

El problema es que he usado fseek para insertar \ y \ n siempre que la longitud exceda 80, por lo que anula dos caracteres de esa línea que exceden la longitud 80. ¿Hay alguna forma de utilizar el texto sin sobreescribir el texto existente?

Aquí está mi código:

#include #include int main(int argc, char *argv[]) { FILE *fp1,*fp2; int prev=0,now=0; char ch; int flag=0; long cur; fp1=fopen(argv[1],"r+"); if(fp1==NULL){ printf("Unable to open the file to read. Program will exit."); exit(0); } else{ while((ch=fgetc(fp1))!=EOF){ if(ch!=' ' && ch!='\n'){ now=now+1; } else{ if(now>=80){ fseek(fp1,cur,SEEK_SET); fputc('\\',fp1); fputc('\n',fp1); now=0; continue; } if(ch=='\n'){ flag=0; now=0; continue; } else{ prev=now; cur=ftell(fp1); } now=now+1; } } } fclose(fp1); return 0; } 

Para ejecutarlo, debe hacer lo siguiente:

 user@ubuntu$ cc xyz.c user@ubuntu$ ./a.out file_to_check.txt 

No, no hay forma de insertar caracteres en un archivo existente. Tendrá que usar un segundo archivo para hacer eso.

Si bien hay un par de técnicas para hacerlo en el lugar, está trabajando con un archivo de texto y desea realizar inserciones. Los sistemas operativos generalmente no son compatibles con las inserciones de archivos de texto como una primitiva del sistema de archivos y no hay ninguna razón para que lo hagan.

La mejor manera de hacer ese tipo de cosas es abrir su archivo para leer, abrir un nuevo archivo para escribir, copiar la parte del archivo antes del punto de inserción, insertar los datos, copiar el rest y luego mover el nuevo archivo el viejo.

Esta es una técnica común y tiene un propósito. Si algo sale mal (por ejemplo, con su sistema), todavía tiene el archivo original y puede repetir la transacción más tarde. Si inicia dos instancias del proceso y utiliza un patrón específico, la segunda instancia puede detectar que la transacción ya se ha iniciado. Con el acceso exclusivo a archivos, incluso puede detectar si la transacción se interrumpió o aún se está ejecutando.

De esa manera, es mucho menos propenso a errores que cualquiera de las técnicas realizadas directamente en el archivo original y es utilizado por todas esas herramientas tradicionales como sed incluso si les pides que trabajen en el lugar ( sed -i ). Otra ventaja es que siempre puede cambiar el nombre del archivo original por uno con un sufijo de copia de seguridad antes de sobrescribirlo ( sed ofrece esa opción).

La misma técnica se utiliza a menudo para los archivos de configuración, incluso si su progtwig está escribiendo una versión completamente nueva y no utiliza el archivo original para eso. No ha pasado mucho tiempo desde que muchas revistas de Internet afirmaron que ext4 trunca accidentalmente los archivos de configuración a longitud cero. Esto fue exactamente porque algunas aplicaciones mantuvieron los archivos de configuración abiertos y truncados mientras el sistema se cerraba forzosamente. Esas aplicaciones a menudo manipularon los archivos de configuración originales antes de que tuvieran los datos listos y luego los mantuvieron abiertos sin sincronizarlos, lo que hizo que la ventana de corrupción de datos fuera mucho más grande.

TL; DR versión:

Cuando valoras tus datos, no los destruyas antes de que tengas listos los datos de reemplazo.

No, no hay forma. Debe crear un nuevo archivo o mover los contenidos del archivo 2 caracteres hacia atrás.

Esta es la función que uso para este tipo de cosas:

 int finsert (FILE* file, const char *buffer) { long int insert_pos = ftell(file); if (insert_pos < 0) return insert_pos; // Grow from the bottom int seek_ret = fseek(file, 0, SEEK_END); if (seek_ret) return seek_ret; long int total_left_to_move = ftell(file); if (total_left_to_move < 0) return total_left_to_move; char move_buffer[1024]; long int ammount_to_grow = strlen(buffer); if (ammount_to_grow >= sizeof(move_buffer)) return -1; total_left_to_move -= insert_pos; for(;;) { u16 ammount_to_move = sizeof(move_buffer); if (total_left_to_move < ammount_to_move) ammount_to_move = total_left_to_move; long int read_pos = insert_pos + total_left_to_move - ammount_to_move; seek_ret = fseek(file, read_pos, SEEK_SET); if (seek_ret) return seek_ret; fread(move_buffer, ammount_to_move, 1, file); if (ferror(file)) return ferror(file); seek_ret = fseek(file, read_pos + ammount_to_grow, SEEK_SET); if (seek_ret) return seek_ret; fwrite(move_buffer, ammount_to_move, 1, file); if (ferror(file)) return ferror(file); total_left_to_move -= ammount_to_move; if (!total_left_to_move) break; } seek_ret = fseek(file, insert_pos, SEEK_SET); if (seek_ret) return seek_ret; fwrite(buffer, ammount_to_grow, 1, file); if (ferror(file)) return ferror(file); return 0; } 

Úselo así:

 FILE * file= fopen("test.data", "r+"); ASSERT(file); const char *to_insert = "INSERT"; fseek(file, 3, SEEK_SET); finsert(file, to_insert); ASSERT(ferror(file) == 0); fclose(file); 

Esto (como han mencionado otros aquí) teóricamente puede dañar un archivo si hay un error, pero aquí hay un código para hacerlo ... Hacerlo in situ de esta manera generalmente está bien, pero debes hacer una copia de seguridad del archivo si están preocupados por eso ...

Puede cargar el archivo como fragmentos (en su caso son 80 caracteres) y luego agregar dos caracteres (nueva línea) y escribir el contenido en un archivo adicional.