【问题标题】:Replace line in text-file using C使用 C 替换文本文件中的行
【发布时间】:2011-10-12 06:54:07
【问题描述】:

我想使用 C 将文本文件中包含 # 符号的行更改为 heet

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

是否有任何其他技巧可以从文件中删除或删除整行?所以,我们可以很容易地替换它。

myfile.txt: (执行前)

Joy
#Smith
Lee
Sara#
Priyanka
#Addy

代码:

#include <stdio.h>
#include <string.h>

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  

【问题讨论】:

  • 用字符串数组备份代码中的所有文件然后用空白文件替换整个文件然后将备份写入文件并应用我们需要的更改是否很好???

标签: c file


【解决方案1】:

做你想做的最好的方法是使用像 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 如何工作的解释,但我的 google karma 似乎找不到它。

编辑: 如何使用 sed:

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

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

上面的命令解释为:

将任何包含# 的行替换为heet。最后的 g 告诉 sed 全局执行此操作,即在整个文件中。

编辑2: 默认情况下,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 脚本中。

【讨论】:

  • 你能用例子解释一下如何在代码中使用 SED
  • 感谢 klas,它可以按我的意愿在终端上运行和回显,但它不会编辑文件,我想将其包含在我的代码中,而不是通过终端中的命令手动执行
【解决方案2】:

您可能应该将输入/输出视为 UNIX 实用程序,并通过读取整个输入并写入整个输出来替换该行,就像 sed 会或其他东西一样。编辑该行会很痛苦,因为您需要将以下文本“向下”移动以使其正常工作。

【讨论】:

    【解决方案3】:

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

    还要注意这些重要问题:

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

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

    替换文件中的文字有2种方式:

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

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

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    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;
    }
    

    【讨论】:

      【解决方案4】:

      要使用fwrite 或任何文件写入函数重写文件中的单词,请使用fgetposfsetpos。否则单独寻找文件指针是行不通的。还是这样,如果文件指针是文件的结尾,就意味着追加是可能的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-07
        • 1970-01-01
        • 2013-09-02
        • 1970-01-01
        • 2016-08-08
        • 2021-01-12
        相关资源
        最近更新 更多