C函数在文件中的特定位置插入文本,而不会覆盖现有的文本
我写了一个程序,它将一个文件作为input,并且每当它find一个长度大于80的行时,它就会将\和\ n添加到该文件中,使其最大宽度为80个字符。
问题是我已经使用fseek插入\和\ n每当长度超过80,所以它覆盖该行超过长度80的两个字符。有没有一种方法,我可以插入文本,而不会覆盖现有的文本?
这是我的代码:
#include<stdio.h> #include<string.h> 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; }
运行它,你需要做以下事情: –
user@ubuntu$ cc xyz.c user@ubuntu$ ./a.out file_to_check.txt
不,没有办法将字符插入到现有文件中。 您将需要使用第二个文件来做到这一点。
虽然有两种技术可以在原地进行,但您正在使用文本文件并希望执行插入操作。 操作系统通常不支持文本文件插入作为文件系统原语,他们没有理由这样做。
做这种事情的最好方法是打开文件进行阅读,打开一个新的文件进行写入,在插入点之前复制文件的一部分,插入数据,复制剩余的文件,然后移动新的文件旧的。
这是一个常用的技术,它有一个目的。 如果出现任何问题(例如在您的系统中),您仍然拥有原始文件,并可以在稍后重复该事务。 如果启动进程的两个实例并使用特定模式,则第二个实例能够检测到事务已经启动。 通过专有的文件访问,甚至可以检测事务是否中断或仍在运行。
这种方式比直接在原始文件上执行的任何技术都要less得多,即使你要求它们在原地工作( sed -i
),所有这些传统工具(如sed
也会使用这种技术。 另外一个好处是你可以在覆盖之前将原始文件重命名为带有备份后缀的文件( sed
提供这样的选项)。
即使您的程序正在编写一个全新的版本并且不使用原始文件,configuration文件也经常使用相同的技术。 因为很多networking杂志都声称ext4意外地将configuration文件截断为零。 这正是因为一些应用程序在系统被强制closures的时候保持了configuration文件的打开和截断。 这些应用程序在准备好数据之前通常会篡改原始configuration文件,甚至在不同步的情况下保持打开状态,从而使得数据损坏的窗口变得更大。
TL; DR版本:
当您重视您的数据时,请勿在准备好replace数据之前将其销毁。
不,没有办法。 您必须创build一个新文件或将文件的内容向后移动2个字符。
这是我用于这种事情的function:
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; }
像这样使用它:
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);
这个(正如其他人在这里提到的那样)在理论上可以在文件出现错误的情况下破坏文件,但是这里有一些代码来实际执行它…像这样就地操作通常很好,但是如果你需要备份文件担心它…
你可以加载文件(在你的情况下是80个字符),然后附加两个字符(换行),并将内容写入anohter文件。