如何用fopen()选择开放模式?

时间:2012-05-13 18:00:38

标签: c linux file-io fopen

我对fopen()的文件打开模式有疑问。

在我的情况下,我想自由地寻找光标,有时可能甚至超过EOF。更重要的是,我还想附加到它而不是截断现有文件。我试图以a+模式打开文件;但是,我不能自由地寻找文件光标。每当我寻找超出EOF的光标时,新到达数据将附加到文件的末尾,而不是我指定的位置。而如果在w+模式下打开,则现有文件将被截断。这个问题有完美的解决方案吗?


更新:

未明确指出的一点是该文件可能并不总是存在;在这种情况下,我必须创建一个新文件。

实际上,我想处理一个配置文件。我不知道这样做是否是好的做法。或者我应该首先放置一个空的配置文件。因此没有必要关心案例文件不存在吗?

以下是代码段:

FILE *f = fopen(FILE_PATH, "wb+");
struct record r;
if (f) {
    if (fread((void *)&r, 1, sizeof(struct record), f) {
        /* File exists, do the normal flow */
    } else {
        if (feof(f)) {
            /* File is newly created, do some initialization */
        }
    }
} else {
    /* issue a warning */
}

3 个答案:

答案 0 :(得分:6)

您必须分两个阶段处理可能不存在的文件,首先假设它存在然后处理它的缺席:

if ((f = fopen(filename, "rb+") == 0)
    f = fopen(filename, "wb+");
if (f == 0)
    ...report error...

"rb+"模式将无法打开不存在的文件(但其他行为符合您的要求)。如果该文件不存在,则"wb+"将执行您想要的操作(尽管它仍然可能失败,例如,如果该文件存在但您没有写入它的权限)。你必须希望你没有受到双重尝试的TOCTOU(检查时间,使用时间)攻击。

另一种方法是使用带有适当标志的open()系统调用的3参数版本来打开文件描述符,然后使用fdopen()从文件描述符创建文件流:

#include <fcntl.h>

int fd;
if ((fd = open(filename, O_RDRW | O_CREAT, 0644)) >= 0)
    f = fdopen(fd, "rb+");

您可以使用标记精确控制open()

答案 1 :(得分:2)

fopen(在Unix / Linux / OS X上尝试man 3 fopen)清楚地记录了文件模式。

  

r+开放阅读和写作。流位于文件的开头。

答案 2 :(得分:-1)

嗨,您可以使用“w +”来读取和写入fseek,我写了一个小的演示程序,首先将数据写入文件并使用fseek将每个数据间隔设置为某个字节,然后读取它:

#include <stdio.h>
#include <unistd.h>

#define FILE_PATH "seek_test.txt"
#define STEP_SIZE 64

void set_data(FILE* fp)
{
    int i = 0;
    fseek(fp, 0, SEEK_SET);

    for ( ; i < 20; ++i)
    {
        fprintf(fp, "%d", i);
        fseek(fp, STEP_SIZE, SEEK_CUR);
    }
}

void get_data(FILE* fp)
{
    int i = 0;
    fseek(fp, 0, SEEK_SET);

    for ( ; i < 20; ++i)
    {
        fscanf(fp, "%d", &i);
        fprintf(stderr, "Cur Step: %5ld, value = %4d\n", i * STEP_SIZE, i);
        fseek(fp, STEP_SIZE, SEEK_CUR);
    }
}

int main(int argc, char* argv[])
{
    FILE* fp = fopen(FILE_PATH, "w+");
    if (fp == NULL)
    {
        printf("fopen Error\n");
        exit(0);
    }

    set_data(fp);
    get_data(fp);

    return 0;
}

=============================== 结果如下:

Cur Step:0,value = 0

Cur Step:64,value = 1

Cur Step:128,value = 2

Cur Step:192,value = 3

Cur步骤:256,值= 4

Cur步骤:320,值= 5

Cur步骤:384,值= 6

Cur步骤:448,值= 7

Cur步骤:512,值= 8

Cur步骤:576,值= 9

Cur步骤:640,值= 10

Cur步骤:704,值= 11

Cur Step:768,value = 12

Cur步骤:832,值= 13

Cur步骤:896,值= 14

Cur Step:960,value = 15

Cur Step:1024,value = 16

Cur步骤:1088,值= 17

Cur步骤:1152,值= 18

Cur Step:1216,value = 19

=============================