«

C语言如何实现随机读写文件

时间:2024-8-6 09:04     作者:韩俊     分类: Java


这篇文章主要讲解了“C语言如何实现随机读写文件”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C语言如何实现随机读写文件”吧!

1.fseek

前面已经剧透过了,fseek可以改变记录读写位置的指针的指向,从而实现文件的随机读写。该函数的声明如下:

int fseek ( FILE * stream, long int offset, int origin );

第一个参数大家都很熟悉了,就是一个文件指针,告诉fseek我现在操作的是哪个文件。

第二个参数,offset是偏移量的意思,大家先记住。第三个参数,origin,顾名思义,即“起始位置”。后面两个参数让人摸不着头脑,但是配合起来就很有意思了。

举个例子:假设一个文件中存有abcdefg,当你用fopen打开这个文件时,一个记录读写位置的指针就指向了起始位置,也就是指向了a。如果我想读取第5个字符,即e呢?那我就要让这个指针指向e,这样再fgetc就能读到e了。

我可以这样算:e相对于起始位置a,向右偏移了4个字符,因为相对于a,a自己的偏移量是0,b是1,c是2,d是3,e自然是4。那么,偏移量offset(fseek的第二个参数)就是4,这个4是相对于起始位置的,这个“相对于”哪里,也就是origin(fseek的第三个参数)的位置,此时origin就是“起始位置”,明白了吧。而fseek用一个宏SEEK_SET来表示“起始位置”,所以此时fseek的调用如下:

fseek(pf, 4, SEEK_SET);

下面我们来验证一下。先在工程目录下创建一个文件,文件名是test.txt,然后在里面输入abcdefg。

按照打开文件->读文件->关闭文件的顺序,写代码:

#include <stdio.h>

int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    fseek(pf, 4, SEEK_SET);
    putchar(fgetc(pf));

    fclose(pf);
    pf = NULL;

    return 0;
}

打开文件后,使用fseek让记录读写位置的指针指向e,接着用fgetc读取e并用putchar打印出来,输出结果如下:

我们就成功跳过了前面的abcd,直接读取到e,实现了文件的随机读写。

当然,读取到e不止有这一种写法。fseek的第三个参数origin有三种取值,分别是:

1.SEEK_SET,表示起始位置。

2.SEEK_CUR,表示当前指向的位置。

3.SEEK_END,表示文件末尾。

SEEK_SET和SEEK_CUR都很好理解,需要注意的是,SEEK_END不是指向最后一个字符,而是指向最后一个字符的下一个位置。比如,一个文件中存有abcdefg,SEEK_END不是指向g,而是指向g的下一个位置。所以同样是读到e,如果origin是SEEK_END,offset就应该是-3,因为g的偏移量是-1,f是-2,所以e是-3。把上面代码中的fseek的调用方式改一下,其他不变:

fseek(pf, -3, SEEK_END);

也可以读到e,因为在执行完上面这行代码后,记录读写位置的指针就指向了e,所以读取时就跳过了前面的abcd,直接读到e。说明一下,由于读写前该指针指向了e,调用fgetc读完e后,该指针就指向了e后面的f,也就是说,此时SEEK_CUR就指向了f,如果我们想读到b呢?可以数一下,abcdefg,b相对于SEEK_CUR(指向f)的偏移量就是-4,如果像下面的代码这样写:

#include <stdio.h>

int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    fseek(pf, -3, SEEK_END); // 指向e
    putchar(fgetc(pf)); // 读完e后指向f

    fseek(pf, -4, SEEK_CUR); // 指向b
    putchar(fgetc(pf)); // 读完b后指向c

    fclose(pf);
    pf = NULL;

    return 0;
}

输出结果如下:

2.ftell

我如果想知道此时记录读写位置的指针相对于起始位置的偏移量(即相对于SEEK_SET的偏移量)是多少,就可以问问ftell函数。该函数声明如下:

long int ftell ( FILE * stream );

ftell会返回当前相对于起始位置的偏移量。比如前面的例子中调用:

#include <stdio.h>

int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    fseek(pf, -3, SEEK_END); // 指向e
    putchar(fgetc(pf)); // 读完e后指向f

    fseek(pf, -4, SEEK_CUR); // 指向b
    putchar(fgetc(pf)); // 读完b后指向c

    printf("
%ld
", ftell(pf));

    fclose(pf);
    pf = NULL;

    return 0;
}

由于此时记录文件读写位置的指针指向了c,偏移量是2(a为0,b为1,c为2),所以会输出2。

3.rewind

rewind的作用是,让指向文件读写位置的指针指向文件的起始位置。该函数声明如下:

void rewind ( FILE * stream );

其实非常简单,rewind(pf);和fseek(pf, 0, SEEK_SET);是等价的。

在前面的例子中,记录文件读写位置的指针左右横跳,最后指向了c,此时ftell也返回了2,这时如果我rewind一下,该指针就又指向了起始位置,即a,再ftell就能知道偏移量回到了0,如果再fgetc,就能重新读取到a了。代码如下:

#include <stdio.h>

int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        return 1;
    }

    fseek(pf, -3, SEEK_END); // 指向e
    putchar(fgetc(pf)); // 读完e后指向f

    fseek(pf, -4, SEEK_CUR); // 指向b
    putchar(fgetc(pf)); // 读完b后指向c

    printf("
%ld
", ftell(pf));

    rewind(pf);
    printf("%ld
", ftell(pf));
    putchar(fgetc(pf)); // a

    fclose(pf);
    pf = NULL;

    return 0;
}

输出结果:

当然,把上述代码中的rewind(pf);换成fseek(pf, 0, SEEK_SET);的效果是一样的。

标签: java

热门推荐