5

我正在玩弄一些打开、读取和修改文本文件的代码。一个快速(简化)的例子是:

#include <stdio.h>
int main()
{
    FILE * fp = fopen("test.txt", "r+");
    char line[100] = {'\0'};
    int count = 0;
    int ret_code = 0;
    while(!feof(fp)){
        fgets(line, 100, fp);
        // do some processing on line...
        count++;
        if(count == 4) {
          ret_code = fprintf(fp, "replaced this line\n");
          printf("ret code was %d\n", ret_code);
          perror("Error was: ");
        }
    }
    fclose(fp);
    return 0;
}

现在在 Linux 上,使用 gcc (4.6.2) 编译此代码运行,并修改文件的第 5 行。在使用 Visual C++2010 编译的 Windows7 上运行的相同代码运行并声称已成功(报告 19 个字符的返回代码并perror显示“无错误”)但未能替换该行。

在 Linux 上,我的文件具有完全权限:

-rw-rw-rw- 1 mike users 191 Feb 14 10:11 test.txt

据我所知,在 Windows 上也是如此:

test.txt(右键单击)-> 属性-> 安全性
“允许”检查用户、系统和管理员的读写。

我在 Windows 上使用 MinGW 的 gcc 得到了相同的结果,所以我知道它不是 Visual C++“功能”。

我是否遗漏了一些明显的东西,或者我没有收到错误,但也没有输出只是在 Windows上使用r+with的一个未记录的“功能”?fopen()


编辑:
似乎即使在微软的网站上,他们也说“r+”应该打开阅读写作。他们还做了这样的说明:

当指定“r+”、“w+”或“a+”访问类型时,允许读取和写入(文件被称为“更新”打开)。但是,当您在读取和写入之间切换时,必须有中间的 fflush、fsetpos、fseek 或 rewind 操作。如果需要,可以为 fsetpos 或 fseek 操作指定当前位置。

所以我尝试了:

        ...
        if(count == 4) {
          fflush(fp);
          ret_code = fprintf(fp, "replaced this line\n");
          fflush(fp);
          printf("ret code was %d\n", ret_code);
          ...

无济于事。

4

2 回答 2

3

根据Linux手册页fopen()

读和写可以以任何顺序在读/写流上混合。请注意,ANSI C 要求文件定位函数在输出和输入之间进行干预,除非输入操作遇到文件结尾。(如果不满足此条件,则允许读取返回除最近写入之外的写入结果。)因此,放置 fseek(3) 或 fgetpos(3 ) 对此类流的写入和读取操作之间的操作。这个操作可能是一个明显的无操作(如 fseek(..., 0L, SEEK_CUR) 调用它的同步副作用。

因此,在从文件读取和写入之间切换时,您应该始终调用fseek()(例如)。fseek(..., 0, SEEK_CUR)

于 2013-02-14T16:05:05.617 回答
3

在输入后执行输出之前,anfflush()没有任何好处 - 您需要执行查找操作。就像是:

fseek(fp, ftell(fp), SEEK_SET); // not fflush(fp);

来自 C99 标准(7.19.5.3/6“fopen 函数):

当以更新模式打开文件时(“+”作为上述模式参数值列表中的第二个或第三个字符),可以在关联的流上执行输入和输出。但是,如果没有对 fflush 函数或文件定位函数(fseek、fsetpos 或 rewind)的干预调用,则输出不应直接跟随输入,并且在没有对文件定位的干预调用的情况下,输入不应直接跟随输出函数,除非输入操作遇到文件结尾。

于 2013-02-14T16:09:52.540 回答