【问题标题】:Does fseek() move the file pointer to the beginning of the file if it was opened in "a+b" mode?如果文件以“a+b”模式打开,fseek() 是否会将文件指针移动到文件的开头?
【发布时间】:2011-07-28 18:58:20
【问题描述】:

我希望使用“a+b”模式打开一个文件,即如果它不存在,它会自动创建,但如果它存在,我不想覆盖它。我希望能够读取和写入文件。

该文件是二进制文件,我想在其中保存特定struct 的记录。所以我想对我想要的记录做fseek(),然后使用fwrite()保存记录。

代码如下所示(MyRecordtypedefstruct,而FILENAME#define 到文件名):

int saveRecord(MyRecord *pRecord, int pos)
{
    FILE* file = fopen(FILENAME, "a+b");
    if (file == NULL)
    {
        printf("Unable to open file %s\n", FILENAME);
        return 0;
    }

    fseek(file, pos * sizeof(MyRecord), SEEK_SET);
    fwrite(pRecord, sizeof(MyRecord), 1, file);
    fclose(file);
    return 1;
}

但是,即使我将 pos 设置为 0,此代码也只是将记录附加到文件末尾。为什么 fseek()SEEK_SET 不能在附加模式下工作?

我知道我可以简单地用“r+b”打开它,如果它失败了用“wb”打开它,但我想知道为什么这不起作用以及为什么 fseek()SEEK_SET 会离开文件指针在末尾。对记录此行为的地方的任何引用表示赞赏(因为我找不到任何地方,或者我使用了错误的关键字)。

【问题讨论】:

    标签: c append fopen fseek


    【解决方案1】:

    使用“r+b”模式,如果失败则回退到“w+b”。

    “a+b”模式,允许阅读和追加; "r+b" 允许随机读写。

    fopen 的文档描述了文件在不同模式下的行为方式。

    【讨论】:

    • 这有一个竞争条件会破坏你的文件。
    • @R..:什么比赛条件?如果errno == ENOENT 失败,我应该说“回退到“wb”吗?
    • 我假设一个多任务操作系统,在第一次 fopen 失败后但在第二次 fopen 尝试之前,另一个进程可以创建文件并用数据填充它。如果 OP 正在处理一个嵌入式系统或任何已知不会发生这种情况的封闭系统,这可能不是问题。
    • 我看到@R.. 谢谢。如果这是一个问题fwrite 到同一位置同时由不同的进程也是一个问题; OP 可以使用相同的方法来管理这两个问题。
    【解决方案2】:

    Plain C 没有任何理智的方法可以实现您想要的。如果您使用的是 POSIX 系统或任何远程关闭的系统,您可以使用fd=open(FILENAME, O_CREAT|O_RDRW, 0666),然后使用fdopen(fd, "rb+")

    编辑:您可以尝试另一件事,使用普通 C:

    f = fopen(FILENAME, "a+b");
    if (!f) /* ... */
    tmp = freopen(0, "r+b", f);
    if (tmp) f = tmp;
    else /* ... */
    

    【讨论】:

    • 是的,我想这会奏效。我需要这个才能在纯 ANSI C 上工作。仍然为您 +1 以作为不错的选择。
    • 您尝试过freopen 解决方案吗?不知道它在实践中是否有效(freopen 指定不明确,理论上可能没用)但它可能没问题。
    【解决方案3】:

    这是因为在a 模式下,写入FILE* 总是附加到末尾。 fseek 仅在此模式下设置读取指针。这记录在 C 标准 7.19.5.3 fopen

    以附加模式打开文件('a' 作为模式参数中的第一个字符) 导致对文件的所有后续写入被强制到当前的文件结尾, 不管对 fseek 函数的调用是否干预。

    【讨论】:

      猜你喜欢
      • 2014-11-19
      • 1970-01-01
      • 2016-09-13
      • 1970-01-01
      • 2012-05-24
      • 2015-04-23
      • 2019-12-09
      • 1970-01-01
      • 2016-01-04
      相关资源
      最近更新 更多