【问题标题】:Find and replace specific string in a text file, without creating new file在文本文件中查找和替换特定字符串,而不创建新文件
【发布时间】:2018-05-24 04:51:08
【问题描述】:

以下代码获取一个原始 txt 文件,一个要在文件中搜索的字符串,以及一个替换原始字符串的新字符串。两个字符串的长度相同。此代码创建一个新文件(“new.txt”),将替换的文本写入那里,然后删除原始文件并将新文件重命名为原始文件。

问题是,我怎样才能使这段代码功能相同但不创建新文件?换句话说,我只想修改原始文件本身。我对原始文件(f)尝试了 fprintf,但它的输出很奇怪。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 1024

int main(int argc, char *argv[])
{
    FILE *f = fopen(argv[1], "r+");
    FILE *f2 = fopen("new.txt", "a+");

    if(strlen(argv[2])!=strlen(argv[3]))
        printf("[%s] and [%s] have different lengths\n", argv[2], argv[3]);

    char write[MAX];
    int where;
    char* string = NULL;

    int len = strlen(argv[2]);
    int i=0;

    while(fgets(write, MAX, f)!=NULL)
    {
        if(NULL!=(string = strstr(write, argv[2])))
        {
            where = (int)(string - write);
            strncpy(write+where, argv[3], len);
        }
        fprintf(f2, "%s", write);
    }
    remove(argv[1]);
    rename("new.txt", argv[1]);
    return 0;
}

【问题讨论】:

  • 如果我想就地工作,我可能只需要mmap 文件。
  • 使用 fputs 写入同一个文件。
  • 检查fseek
  • fseek 到文件中第一次更改发生的位置,然后 fwrite 直到不需要进一步更改的位置。如果您要插入一行,那基本上意味着覆盖从该行到文件末尾的所有内容。但这实际上在文件系统上创建了一个新文件,它恰好具有相同的名称。与简单地写入新文件、删除原始文件并重命名新文件相比,数据的查找和写入将使文件锁定更长的时间。
  • 在花时间打开文件之前检查字符串长度会更好——文件打开速度很慢,尤其是在创建文件时。当然,您最终只会使用一个文件。您需要跟踪每行的开始位置,以便您可以进行替换,寻找到您需要替换、写入和再次寻找的开始(从当前位置寻找零字节就足够了),然后再继续读。您必须在每个读取序列和下一次写入之间以及一系列写入(在本例中为一次)和下一次读取之间进行定位操作。

标签: c string file


【解决方案1】:

简短的回答是您确实不应该这样做,但如果搜索和替换字符串的长度完全相同,这是可行的——但你不能在你写的字符数上犯任何错误——否则你会破坏文件。

在您的代码中,如果strlen 不一样,您需要return 或以其他方式处理错误,而不仅仅是输出该事实。

您已经将f"r+" 开头并带有文件位置指示符,strstr 会告诉您是否找到要替换的单词,然后您需要做的就是设置文件-positon-indicator 到 strstr 返回的指针的位置,并将替换字符写入搜索词,并在该行的其余部分重复。

需要特别注意保持文件位置指示符的偏移量。阅读后,指示器将超过fgets 读取的最后一个字符,因此您需要在代码中备份where - write - strlen(write)。 (注意:偏移量是负数)

您可以使用fseek 来回退和重置文件位置指示器,但您最好使用fgetpos 保存当前指标位置并使用fsetpos 恢复它,同时仅调用fseek一次定位到更换指示器。

举一个简短的例子,使用buffindreplace,而不是writewhere,您可以执行以下操作:

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

#define MAXC 1024

int main (int argc, char **argv) {

    char buf[MAXC], *find, *replace;    /* read buf, find, replace pointers */
    size_t findlen;     /* length of find string */
    FILE *f = NULL;     /* file pointer */

    if (argc < 4 ) {    /* validate sufficient arguments given */
        fprintf (stderr, "error: insufficient input, "
                "usage: %s file find repl\n", argv[0]);
        return 1;
    }
    find = argv[2];     /* set find, replace & length */
    replace = argv[3];
    findlen = strlen (find);

    if (findlen != strlen (argv[3])) {  /* validate length the same */
        fprintf (stderr, "error find/replace lengths differ.\n");
        return 1;
    }

    if (!(f = fopen (argv[1], "r+"))) {  /* validate file open for reading+ */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (buf, MAXC, f)) {  /* read each line into buf */
        char *findp = buf;          /* find pointer to search buf */
        /* 
         * buf length and search term split at end validation omitted.
         */
        while ((findp = strstr (findp, find))) {    /* while find found */
            fpos_t pos;         /* object to hold current file position */
            /* compute characters to backup (negative) */
            long backup = (long)(findp - buf) - strlen(buf);

            fgetpos (f, &pos);              /* save the current position */
            fseek (f, backup, SEEK_CUR);    /* backup */

            for (char *p = replace; *p; p++)
                fputc (*p, f);  /* overwrite char-by-char */

            fsetpos (f, &pos);  /* reset file position */

            findp += findlen;   /* advance beyond current find */
        }
    }

    if (fclose (f) == EOF)    /* validate close after write */
        perror ("fclose(f)");

    return 0;
}

输入文件示例

$ cat dat/dogfleas.txt
my dog has fleas
other dogs run away
my dog is an ichy dog

使用示例和生成的文件

$ ./bin/file_replace_in_place dat/dogfleas.txt dog cat

$ cat dat/dogfleas.txt
my cat has fleas
other cats run away
my cat is an ichy cat

shell 命令中没有双关语

【讨论】:

    猜你喜欢
    • 2013-11-28
    • 1970-01-01
    • 1970-01-01
    • 2012-08-25
    • 2011-05-25
    • 2015-07-23
    • 2014-06-21
    • 2013-02-19
    • 2020-08-12
    相关资源
    最近更新 更多