3

我有一个关于文件打开模式的问题fopen()

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


更新:

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

其实我想处理一个配置文件。我不知道这样实施是否是一种好习惯。或者我应该先放置一个空的配置文件。这样有没有必要关心case文件不存在?

下面是代码片段:

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 */
}
4

3 回答 3

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()您可以通过标志获得相当精确的控制。

于 2012-05-13T18:41:05.060 回答
2

文件模式已明确记录fopen(尝试man 3 fopen在 Unix/Linux/OS X 上)。

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

于 2012-05-13T18:04:25.980 回答
-1

你好,fseek可以用"w+"读写,我写了一个小demo程序,先把数据写入文件,然后用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;
}

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

当前步长:0,值 = 0

当前步长:64,值 = 1

当前步长:128,值 = 2

当前步长:192,值 = 3

当前步长:256,值 = 4

当前步长:320,值 = 5

当前步长:384,值 = 6

当前步长:448,值 = 7

当前步长:512,值 = 8

当前步长:576,值 = 9

当前步长:640,值 = 10

当前步长:704,值 = 11

当前步长:768,值 = 12

当前步长:832,值 = 13

当前步长:896,值 = 14

当前步长:960,值 = 15

当前步长:1024,值 = 16

当前步长:1088,值 = 17

当前步长:1152,值 = 18

当前步长:1216,值 = 19

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

于 2012-05-14T06:21:38.197 回答