使用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()
删除原始文件,并使用renameremove()
将临时文件重命名为原始名称。 此方法在存储设备上使用额外空间,并要求您可以创建新文件并确定与现有文件名不冲突的文件名。 - 或者,您可以读取原始文件的完整内容,并从一开始就使用修改后的内容覆盖它。 这是因为修改后的内容比原始内容长。 如果文件非常大并且不适合内存,则此方法可能会失败,这对于常规文本文件来说相当罕见。
这是使用第二种方法的修改版本:
#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重写文件中的单词,请使用fgetpos
和fsetpos
。 否则单独寻找文件指针将无法正常工作。 仍然这样做,如果文件指针是文件的末尾,则意味着可以追加。