以下代码获取原始txt文件,要在文件中搜索的字符串以及用于替换原始文件的新字符串。两根弦的长度是相同的。此代码创建一个新文件(“new.txt”),将替换的文本写入其中,然后删除原始文件&将新的重命名为原始文件。
问题是,如何使此代码功能相同但不创建新文件?换句话说,我只想修改原始文件本身。我尝试了fprintf到原始文件(f),但它的输出很奇怪。
#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;
}
答案 0 :(得分:2)
简短的回答是你真的不应该,但是如果搜索和替换字符串的长度完全相同,那么它是可行的 - 但是你不能在你写的字符数上犯任何错误 - 否则你会腐败文件。
在您的代码中,如果strlen
不相同,则需要return
或以其他方式处理错误,而不仅仅是输出该事实。
您已经f
打开了"r+"
,文件位置指示符位于开头,strstr
会告诉您是否找到了要替换的单词,然后您需要的只是要做的是将file-positon-indicator设置为strstr
返回的指针的位置,并在搜索词上写下替换字符,并重复该行的其余部分。
保持文件位置指示器的偏移量需要注意。阅读完毕后,指示符将超过fgets
读取的最后一个字符,因此您需要在代码中按where - write - strlen(write)
进行备份。 (注意:偏移量应为负数)
您可以使用fseek
来快退并重置文件位置指示符,但使用fgetpos
保存当前指标位置并使用fsetpos
还原它可能会更好。同时只调用fseek
一次,以便替换指标。
将它完全放在一个简短的示例中,并使用buf
,find
和replace
代替write
和where
,您可以执行类似的操作以下内容:
#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命令中没有双关语)