C 覆盖文件中的一行

C 覆盖文件中的一行,c,C,我试图覆盖文件中只包含未签名长数字的行。 文件的内容如下所示: 1 2 3 4 5 FILE *f = fopen("timestamps", "r+"); unsigned long times = 0; int pos = 0; while(fscanf(f, "%lu\n", &times) != EOF) { if(times == 3) { fseek(f, pos, SEEK_SET); fprintf(f, "%lu\n"

我试图覆盖文件中只包含未签名长数字的行。 文件的内容如下所示:

1
2
3
4
5
FILE *f = fopen("timestamps", "r+");

unsigned long times = 0;
int pos = 0;
while(fscanf(f, "%lu\n", &times) != EOF)
{
    if(times == 3)
    {
        fseek(f, pos, SEEK_SET);
        fprintf(f, "%lu\n", 0);
    }
    times = 0;
    pos = ftell(f);
}
fclose(f);

f = fopen("timestamps", "r");
times = 0;
while(fscanf(f, "%lu\n", &times) != EOF)
{
    printf("%lu\n", times);
    times = 0;
}
fclose(f);
1
2
10
5
1
2
10

5
我想用数字0替换特定的数字。我编写的代码如下所示:

1
2
3
4
5
FILE *f = fopen("timestamps", "r+");

unsigned long times = 0;
int pos = 0;
while(fscanf(f, "%lu\n", &times) != EOF)
{
    if(times == 3)
    {
        fseek(f, pos, SEEK_SET);
        fprintf(f, "%lu\n", 0);
    }
    times = 0;
    pos = ftell(f);
}
fclose(f);

f = fopen("timestamps", "r");
times = 0;
while(fscanf(f, "%lu\n", &times) != EOF)
{
    printf("%lu\n", times);
    times = 0;
}
fclose(f);
1
2
10
5
1
2
10

5
程序的输出如下所示:

1
2
3
4
5
FILE *f = fopen("timestamps", "r+");

unsigned long times = 0;
int pos = 0;
while(fscanf(f, "%lu\n", &times) != EOF)
{
    if(times == 3)
    {
        fseek(f, pos, SEEK_SET);
        fprintf(f, "%lu\n", 0);
    }
    times = 0;
    pos = ftell(f);
}
fclose(f);

f = fopen("timestamps", "r");
times = 0;
while(fscanf(f, "%lu\n", &times) != EOF)
{
    printf("%lu\n", times);
    times = 0;
}
fclose(f);
1
2
10
5
1
2
10

5
有趣的是,如果我对文件进行cat,它看起来如下所示:

1
2
3
4
5
FILE *f = fopen("timestamps", "r+");

unsigned long times = 0;
int pos = 0;
while(fscanf(f, "%lu\n", &times) != EOF)
{
    if(times == 3)
    {
        fseek(f, pos, SEEK_SET);
        fprintf(f, "%lu\n", 0);
    }
    times = 0;
    pos = ftell(f);
}
fclose(f);

f = fopen("timestamps", "r");
times = 0;
while(fscanf(f, "%lu\n", &times) != EOF)
{
    printf("%lu\n", times);
    times = 0;
}
fclose(f);
1
2
10
5
1
2
10

5

我的
ftell
是否出错?另外,为什么
printf
没有显示
cat
显示的缺失行?

我可以复制并修复

目前的问题是,当您在
r+
中打开一个文件时,必须在每次从读取切换到写入以及从写入切换到读取时调用
fseek

在这里,您可以在写入
0
之前正确地调用
fseek
,但在写入和读取之后调用not。文件指针未正确定位,您将获得未定义的行为

修复很简单,只需更换:

if(times == 3)
{
    fseek(f, pos, SEEK_SET);
    fprintf(f, "%lu\n", 0);
}

但是要当心:它在这里起作用,因为你用一条长度完全相同的线替换一条线。如果您试图将包含1000的行替换为包含0的行,那么在windows系统中,如果行尾为
\r\n
,那么在类unix系统中,如果行尾为
\n
,则会得到一个包含
0
的额外行

因为下面是将会发生的情况(Windows案例):

重写之前:

...  1  0  0  0 \r \n ...
之后:

...  0 \r \n  0 \r \n ...
因为顺序文件是。。。一系列连续的字节

在我看来,更改文本文件最合适的方法是创建一个新的临时文件,逐行复制旧文件,进行任何需要的更改,删除旧文件(或重命名)并重命名临时文件

差不多

char line[1000];
FILE *original, *temporar;
original = fopen("original", "r");
temporar = fopen("temporar", "w");
while (fgets(line, sizeof line, original)) {
    processline(line);
    fprintf(temporar, "%s", line);
}
fclose(temporar);
fclose(original);
unlink("original"); // or rename("original", "original.bak");
rename("temporar", "original");

当然,您需要验证真实代码中的所有调用。

fscanf
@user3666471中删除
\n
,它似乎输出良好;我看到的唯一问题是
fprintf(f,“%lu\n”,0)
应该使用
int
或者
fprintf(f,“%d\n”,0)
long pos=0
fprintf(f,“%lu\n”,0UL);(f)
问题是
3
是一个字符长,而
10
是两个字符长。该文件是
…2\n3\n4\n5…
,现在是
…2\n10\n\n5…
,因为
3\n4
已被
10\n
@francis>取代。但目标是用一个
0
覆盖一个
3
。在这一点上,我认为最好打开一个新文件,并在那里做我想要的更改。在文件中“就地”进行更改是一大罐蠕虫。@user3666471是的!就地替换的唯一用例是具有固定长度记录的(通常为二进制)文件,您可以对其进行随机访问。