使用C替换文本文件中的行

我想在使用C语言的heet更改包含#符号的行。

我已经尝试过这种方式,但它没有彻底运行,它只是替换字符和覆盖而不是整个字符串,就像我想要的那样。

还有其他技巧可以从文件中删除或删除整行吗? 所以,我们可以轻松取代它。

myfile.txt 🙁 执行前)

 Joy #Smith Lee Sara# Priyanka #Addy 

码:

 #include  #include  int main() { FILE *pFile; fpos_t pos1, pos2; int line = 0; char buf[68] char *p; char temp[10] = "heet"; pFile = fopen("myfile.txt", "r+"); printf("changes are made in this lines:\t"); while (!feof(pFile)) { ++line; fgetpos(pFile, &pos1); if (fgets(buf, 68, pFile) == NULL) break; fgetpos(pFile, &pos2); p = strchr(buf, '#'); if (p != NULL) { printf("%d, " , line); fsetpos(pFile, &pos1); fputs(temp, pFile); } fsetpos(pFile, &pos2); } fclose(pFile); return 0; } 

myfile.txt 🙁 执行后)

 Joy heetth Lee heet# Priyanka heety 

输出:

 changes are made in this lines: 2, 4, 6, 

myfile.txt 🙁 我想得到)

 Joy heet Lee heet Priyanka heet 

做你想做的最好的方法是使用像sed这样的工具。 它比你(或我)写的更快,使用更少的内存。

除此之外,让我们假设你想继续自己写吧。

文件就像一个长字节数组。 如果要增加或减少一行的长度,它会影响文件其余部分中每个字节的位置。 结果可能比原始结果更短(或更长)。 由于结果可能更短,因此修改文件是个坏主意。

以下伪代码说明了一种简单的方法:

 open original file open output file allocate a line buffer that is large enough read a line from the original file do return an error if the buffer is too small manipulate the line write the manipulated line to the output file read a line from the original file loop until read returns nothing 

sed做得更聪明。 我曾经看过关于sed如何工作的解释,但我的谷歌业力似乎无法找到它。

编辑:如何使用sed:

  sed -e 's/.*\#.*/heet/g' myfile.txt 

sed的s或substitute命令可以用另一个字符串替换一个字符串或正则表达式。

以上命令解释为:

heet替换任何带有heet 。 最后的g告诉sed全局地这样做,即在整个文件中。

Edit2:默认情况下,sed写入标准输出。 要重写文件,您应该将输出重定向到文件,然后重命名它。 在linux中,执行以下操作(您可以使用system从C运行命令行内容):

 sed -e 's/.*\#.*/heet/g' myfile.txt > temp_file123.txt rm myfile.txt mv temp_file123.txt myfile.txt 

来自C:

 system("sed -e 's/.*\#.*/heet/g' myfile.txt > temp_file123.txt"); system("rm myfile.txt"); system("mv temp_file123.txt myfile.txt"); 

如果只想调用一次system ,只需将所有命令行内容放在shell脚本中即可。

您可能应该像UNIX实用程序一样处理输入/输出,并通过读取整个输入来替换该行,并像sed那样写入整个输出。 编辑线条会很麻烦,因为您需要将以下文本“向下”移动才能使其正常工作。

您无法像在代码中那样覆盖文件来实现目标,因为heet#长3个字节,并且没有标准函数在文件中间插入字节。

还要注意这些重要问题:

  • 你不测试fopen()成功打开文件。 如果文件不存在或无法为读取+更新模式打开,则您具有未定义的行为。
  • while (!feof(pFile))并不完全停止在文件末尾,因为feof()返回的文件结束指示符仅在读取操作失败时设置,而不是之前设置。 你应该写:

      while (fgets(buf, 68, pFile) != NULL) { 
  • 如果文件的行长度超过66个字符,则行号将被错误地计算。

有两种方法可以替换文件中的文本:

  • 您可以创建一个临时文件并将修改后的内容写入其中。 内容全部转换后,使用remove()删除原始文件,并使用rename remove()将临时文件重命名为原始名称。 此方法在存储设备上使用额外空间,并要求您可以创建新文件并确定与现有文件名不冲突的文件名。
  • 或者,您可以读取原始文件的完整内容,并从一开始就使用修改后的内容覆盖它。 这是因为修改后的内容比原始内容长。 如果文件非常大并且不适合内存,则此方法可能会失败,这对于常规文本文件来说相当罕见。

这是使用第二种方法的修改版本:

 #include  #include  #include  int main() { FILE *pFile; int c, line, changes; unsigned char *buf; size_t pos, length, size; char replacement[] = "heet"; /* open the file */ pFile = fopen("myfile.txt", "r+"); if (pFile == NULL) { printf("cannot open myfile.txt\n"); return 1; } /* read the file */ buf = NULL; length = size = 0; while ((c = getc(pFile)) != EOF) { if (length == size) { size = size + size / 2 + 128; buf = realloc(buf, size); if (buf == NULL) { printf("not enough memory to read myfile.txt\n"); fclose(pFile); return 1; } } buf[length++] = c; } /* write the modified contents */ rewind(pFile); line = 1; changes = 0; for (pos = 0; pos < length; pos++) { c = buf[pos]; if (c == '\n') line++; if (c == '#') { if (changes++ == 0) printf("changes are made in this lines:\t"); else printf(", "); printf("%d", line); fputs(replacement, pFile); } else { putc(c, pFile); } } free(buf); fclose(pFile); if (changes == 0) printf("no changes were made\n"); else printf("\n"); return 0; } 

要使用fwrite或任何文件写入function重写文件中的单词,请使用fgetposfsetpos 。 否则单独寻找文件指针将无法正常工作。 仍然这样做,如果文件指针是文件的末尾,则意味着可以追加。