Linux学习日记7:fopen、fclose、fread、fwrite和fseek函数

一、前言

        在之前的内容中,我们已经学习了文件IO范畴的open、close、read、write和lseek函数,也对文件IO与标准IO的核心差异进行了梳理,本文将聚焦于标准IO(C库)体系,深入解析fopen、fclose、fread、fwrite和fseek这几个关键函数的功能、使用场景与技术细节。

二、fopen函数

1、基本定义

        在 Linux 系统中,fopen是标准IO库(C 库)中用于打开文件的核心函数。它封装了底层的系统调用(如open),并提供了缓冲机制,简化了文件操作的复杂度。

2、函数原型

        fopen函数的原型定义在 <stdio.h> 头文件中,原型如下:

#include <stdio.h>

FILE *fopen(const char *pathname, const char *mode);

3、相关参数

        pathname:表示指向字符串的指针,指定要打开的文件路径(可以是相对路径绝对路径)。   比如/home/usr/ll或者ll。

        mode:字符串常量,表示指定文件的打开方式(读写权限、文件创建 / 截断规则等)。Linux 中常用模式如下:

        r:只读方式打开,文件必须存在;

        r+:可读写,文件必须存在;

        rb+:打开二进制文件,可以读写;

        rt+:打开文本文件,可读写;

        w:只写,文件存在则文件长度清0,文件不存在则建立该文件;

        w+:可读写,文件存在则文件长度清0,文件不存在则建立该文件;

        a:附加方式打开只写,不存在建立该文件,存在写入的数据加到文件尾,EOF符保留;

        a+:附加方式打开可读写,不存在建立该文件,存在写入的数据加到末尾,EOF符不保留;

        wb:打开二进制文件,只写;

        wb+:打开或建立二进制文件,可读写;

        wt+:打开或建立文本文件,可读写;

        at+:打开文本文件,可读写,写的数据加在文本末尾;

        ab+:打开二进制文件,可读写,写的数据加在文件末尾;

        注:Linux 系统中不区分文本模式与二进制模式(两者行为一致),这是因为 Linux 文件内容本身就是字节流,没有类似 Windows 的换行符(\n\r\n)转换逻辑。模式中 的仅为兼容其他系统(如 Windows)而存在。

4、返回值

        成功:返回一个非空的 FILE* 指针(文件流对象),后续通过该指针操作文件。

        失败:返回 NULL,同时设置全局变量errno标识错误原因(如文件不存在、权限不足等)。

5、与底层open系统调用的区别

        区别如下:

维度

fopen

open

缓冲机制

自带缓冲,减少系统调用次数

无缓冲,每次操作直接触发系统调用

返回值

FILE*(文件流指针)

整数(文件描述符,fd)

操作接口

需配合fread/fwrite/fclose等

需配合read/write/close等

跨平台性

符合C标准,跨平台(Linux/Windows 等)

依赖 Linux 系统,不跨平台

6、示例

        如下代码所示:

#include<stdio.h>

//FILE *fopen(const char *pathname, const char *mode);

int main()
{
        FILE*fp=NULL;//初始化fp指针,防止野指针
        fp=fopen("file3","w");//创建一个file3文件,并设置只写
        if(fp == NULL)//判断文件是否正常打开
        {
                printf("fopen failed!");
                return -1;
        }
        printf("fopen succeed!");
        return 0;
}

        接着使用gcc编译器进行编译,然后运行文件:

        可以看到文件打开成功。

三、fclose函数

1、基本定义

        在 Linux 系统中,fclose是标准 IO库(C 库)中用于关闭文件流的核心函数,它负责完成文件流的资源释放、缓冲区数据刷新等关键操作。

2、函数原型

        fclose函数的原型定义在 <stdio.h> 头文件中,原型如下:

#include <stdio.h>

int fclose(FILE *stream);

3、参数与返回值

3.1、参数

        stream:类型为FILE*,标识要关闭的目标文件流。

3.2、返回值

        成功:返回0;

        失败:返回EOF(即 -1),同时设置全局变量errno标识错误原因。

4、与底层close系统调用的区别

        区别如下:

维度fclose(标准 I/O)close(系统调用)
操作对象FILE*(文件流指针)整数(文件描述符 fd)
功能范围刷新缓冲区 + 释放标准 I/O 资源 + 调用 close仅关闭文件描述符,无缓冲刷新逻辑
错误处理需通过 errno 或返回值 EOF 判断需通过返回值 0 成功,-1失败)和 errno 判断
跨平台性符合 C 标准,跨平台(Linux/Windows 等)依赖 Linux 系统,不跨平台

5、示例

        接上面fopen那里的例子展开来说,和open、close函数一样,fopen与fclose函数也是密不可分的,如下面代码所示:

#include<stdio.h>

//FILE *fopen(const char *pathname, const char *mode);
//int fclose(FILE *stream);

int main()
{
        FILE*fp=NULL;//初始化fp指针,防止野指针
        fp=fopen("file3","w");//创建一个file3文件,并设置只写
        int ab_fp;
        if(fp == NULL)//判断文件是否正常打开
        {
                printf("fopen failed!\n");
                return -1;
        }
        printf("fopen succeed!\n");
        ab_fp=fclose(fp);//关闭文件流
        if(ab_fp<0)//判断是否关闭成功
        {
                printf("fclose failed!\n");
                return -2;
        }
        printf("fclose succeed!\n");
        return 0;
}

        接着使用gcc编译器进行编译,然后运行文件:

        可以看到文件打开成功、成功关闭。

四、fread函数

1、基本定义

        在 Linux 系统中,fread是标准 IO库(C库)中用于从文件流读取数据的核心函数,它支持二进制安全的读取操作,可用于文本文件和二进制文件的内容读取。

2、函数原型

        fread函数的原型定义在 <stdio.h> 头文件中,原型如下:

#include <stdio.h>

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

3、相关参数

       如下图所示:

参数类型含义
ptrvoid*指向缓冲区的指针,用于存储从文件流中读取的数据。
sizesize_t每个 “数据元素” 的字节大小(例如:读取 int 类型时,int 为 sizeof(int) )。
nmembsize_t要读取的 “数据元素个数”。
streamFILE*要读取的文件流指针(由fopen等函数返回)。

4、返回值

        fread返回实际成功读取的数据元素个数(而非字节数)。

      (1)返回值等于nmemb:表示成功读取了请求的所有元素;

      (2)返回值小于nmemb:可能是遇到了文件末尾(EOF) 或读取错误;

      (3)返回值等于0:表示未读取到任何数据;

5、与底层read系统调用的区别

        区别如下:

维度fread(标准 I/O)read(系统调用)
缓冲机制自带缓冲区(减少系统调用次数,提升效率)无缓冲,每次调用直接触发系统调用
返回值实际读取的元素个数(size_t)实际读取的字节数(size_t)
跨平台性符合 C 标准,跨平台(Linux/Windows 等)依赖 Linux 系统,不跨平台
适用场景需频繁小数据量读取、或读取结构化数据(如结构体)需直接控制底层 I/O、或处理非缓冲场景(如设备文件)

6、示例

        如下代码所示:        

#include<stdio.h>
#include<string.h>

//FILE *fopen(const char *pathname, const char *mode);
//int fclose(FILE *stream);
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
int main()
{
        FILE*fp=NULL;//初始化fp指针,防止野指针
        fp=fopen("file3","r");//创建一个file3文件,并设置只读
        char readbuf[12];//设置一个数组
        memset(readbuf,0,sizeof(readbuf));//初始化数组,防止乱码
        int ab_fp;
        if(fp == NULL)//判断文件是否正常打开
        {
                printf("fopen failed!");
                return -1;
        }
        printf("fopen succeed!\n");
        ab_fp=fread(readbuf,4,2,fp);//将fp文件中的数据读入readbuf这个数组中,数据个数为4*2
        if(ab_fp<=0)
        {
                printf("fread failed!\n");
                return -3;
        }
        printf("read %s\n",readbuf);
        ab_fp=fclose(fp);//关闭文件流
        if(ab_fp<0)//判断关闭是否成功
        {
                printf("fclose failed!");
                return -2;
        }
        printf("fclose succeed!\n");
        return 0;
}

         接着使用gcc编译器进行编译,在创建的文件file3中写入12345678,然后运行文件:

        可以看到成功地将 12345678 8个字节读取了出来。 

        注:如果不初始化数组,会导致乱码。

五、fwrite函数

1、基本定义

        在 Linux 系统中,fwrite是标准 IO库(C 库)中用于向文件流写入数据的核心函数,支持二进制安全的写入操作,可用于文本文件和二进制文件的内容写入。

2、函数原型

         fwrite函数的原型定义在 <stdio.h> 头文件中,原型如下:

#include <stdio.h>

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

3、相关参数

        如下图所示:

参数类型含义
ptrconst void*指向待写入数据缓冲区的指针(数据的源头),const 表示数据在写入过程中不会被修改。
sizesize_t每个 “数据元素” 的字节大小(例如:写入int类型时,sizesizeof(int))。
nmembsize_t要写入的 “数据元素个数”。
streamFILE*要写入的文件流指针(由fopen等函数返回)。

4、返回值

        fwrite返回实际成功写入的 “数据元素个数”(而非字节数)。

      (1)返回值等于nmemb:表示成功写入了请求的所有元素;

      (2)返回值小于nmemb:表示写入过程中出现了错误;

      (3)返回值等于0:表示未写入任何数据;

5、与底层write系统调用的区别

        如下图所示:

维度fwrite(标准 I/O)write(系统调用)
缓冲机制自带缓冲区(减少系统调用次数,提升效率)无缓冲,每次调用直接触发系统调用
返回值实际写入的元素个数size_t实际写入的字节数size_t
跨平台性符合 C 标准,跨平台(Linux/Windows 等)依赖 Linux 系统,不跨平台
适用场景需频繁小数据量写入、或写入结构化数据(如结构体)需直接控制底层 I/O、或处理非缓冲场景(如设备文件)

6、示例

        如下代码所示:

#include<stdio.h>
#include<string.h>

//FILE *fopen(const char *pathname, const char *mode);
//int fclose(FILE *stream);
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

int main()
{
        FILE*fp=NULL;//初始化fp指针,防止野指针
        fp=fopen("file3","r+");//创建一个file3文件,并设置可读可写
        char readbuf[12];//设置一个数组
        char writebuf[]={"hello world"};//设置一个数组,数组内容为“hello world”
        memset(readbuf,0,sizeof(readbuf));//初始化数组,防止乱码
        int ab_fp;
        if(fp == NULL)//判断文件是否正常打开
        {
                printf("fopen failed!");
                return -1;
        }
        printf("fopen succeed!\n");
        ab_fp=fread(readbuf,4,2,fp);//将fp文件中的数据读入readbuf这个数组中,数据个数为4*2
        if(ab_fp<=0)
        {
                printf("fread failed!\n");
                return -3;
        }
        printf("read %s\n",readbuf);
        ab_fp=fwrite(writebuf,4,1,fp);//将writebuf中的数据写入fp文件中,数据个数为4*1
        if(ab_fp<=0)
        {
            printf("fwrite failed\n");
            return -4;
        }
        ab_fp=fclose(fp);//关闭文件流
        if(ab_fp<0)//判断关闭是否成功
        {
                printf("fclose failed!");
                return -2;
        }
        printf("fclose succeed!\n");
        return 0;
}

         接着使用gcc编译器进行编译,然后使用cat指令来查看file3的内容:

        可以看到8后面多了hell这4个字符,说明成功写入(在8后面是因为读取完12345678后光标定在末尾)。

六、fseek函数

1、基本定义

        在 Linux 系统中,fseek是标准 IO库(C 库)中用于移动文件流指针的核心函数,它允许程序在文件中随机定位读写位置,是实现文件随机访问的关键工具。

2、函数原型

        fseek函数的原型定义在 <stdio.h> 头文件中,原型如下:

#include <stdio.h>

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

3、相关参数

       如图所示:

参数类型含义
streamFILE*要操作的文件流指针(由fopen等函数返回)。
offsetlong偏移量(带符号整数):正数表示向后偏移,负数表示向前偏移(需确保偏移后位置有效)。
whenceint定位参考点,取值为以下宏(定义在<stdio.h>中):SEEK_SET文件开头为参考点;SEEK_CUR当前文件指针位置为参考点;SEEK_END文件末尾为参考点。

4、返回值

        成功:返回0;

        失败:返回 EOF(即 -1),同时设置全局变量errno标识错误原因。

5、与底层lseek系统调用的区别

        如下图所示:

维度fseek(标准 I/O)lseek(系统调用)
操作对象FILE*(文件流指针)整数(文件描述符 fd
定位粒度基于long类型偏移量(通常为 4/8 字节,取决于系统)基于off_t类型偏移量(支持更大范围,如 64 位系统下的大文件)
跨平台性符合 C 标准,跨平台(Linux/Windows 等)依赖 Linux 系统,不跨平台
缓冲影响会同步文件流的缓冲区状态(确保指针位置与缓冲数据一致)仅操作底层文件描述符的指针,不影响标准 I/O 的缓冲区

6、示例

        如下代码所示:        

#include<stdio.h>
#include<string.h>

//FILE *fopen(const char *pathname, const char *mode);
//int fclose(FILE *stream);
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
//int fseek(FILE *stream, long offset, int whence);

int main()
{
        FILE*fp=NULL;//初始化fp指针,防止野指针
        fp=fopen("file3","r+");//创建一个file3文件,并设置可读可写
        char readbuf[12];//设置一个数组
        char writebuf[]={"hello world"};//设置一个数组,数组内容为“hello world”
        memset(readbuf,0,sizeof(readbuf));//初始化数组,防止乱码
        int ab_fp;
        if(fp == NULL)//判断文件是否正常打开
        {
                printf("fopen failed!");
                return -1;
        }
        printf("fopen succeed!\n");
        ab_fp=fread(readbuf,4,2,fp);//将fp文件中的数据读入readbuf这个数组中,数据个数为4*2
        if(ab_fp<=0)
        {
                printf("fread failed!\n");
                return -3;
        }
        printf("read %s\n",readbuf);
        ab_fp=fseek(fp,-4,SEEK_CUR);//在当前位置向前偏移4个字节
        if(ab_fp<0)//判断是否偏移成功
        {
                printf("fseek failed\n");
                return -4;
        }
        ab_fp=fwrite(writebuf,4,1,fp);//将writebuf中的数据写入fp文件中,数据个数为4*1
        if(ab_fp<=0)
        {
            printf("fwrite failed\n");
            return -5;
        }
        ab_fp=fclose(fp);//关闭文件流
        if(ab_fp<0)//判断关闭是否成功
        {
                printf("fclose failed!");
                return -2;
        }
        printf("fclose succeed!\n");
        return 0;
}

         接着使用gcc编译器进行编译,然后使用cat指令来查看file3的内容:                可以看到hell这4个字符向前移动了4个字节(需要先提前将原来创建的文件file3先删掉,不然最后结果会是1234hellhell)。

1. fopen函数原型: ```c FILE *fopen(const char *filename, const char *mode); ``` 使用说明: - filename:文件名,可以是相对路径或绝对路径,需要包含文件扩展名。 - mode:访问模式,可以是 `"r"`(只读)、`"w"`(只写)、`"a"`(追加)、`"rb"`(二进制只读)、`"wb"`(二进制只写)、`"ab"`(二进制追加)等。 返回值: - 成功打开文件返回指向该文件的指针。 - 打开文件失败返回 `NULL`。 2. fclose函数原型: ```c int fclose(FILE *stream); ``` 使用说明: - stream:打开文件的指针。 返回值: - 关闭文件成功返回 0。 - 关闭文件失败返回非 0 值。 3. fread函数原型: ```c size_t fread(void *ptr, size_t size, size_t count, FILE *stream); ``` 使用说明: - ptr:指向要读取数据的缓冲区。 - size:每个数据项的字节数。 - count:要读取的数据项数。 - stream:打开文件的指针。 返回值: - 返回实际读取的数据项数,如果该值小于 count,则可能是读取到了文件末尾或者发生了错误。 4. fwrite函数原型: ```c size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream); ``` 使用说明: - ptr:指向要写入数据的缓冲区。 - size:每个数据项的字节数。 - count:要写入的数据项数。 - stream:打开文件的指针。 返回值: - 返回实际写入的数据项数,如果该值小于 count,则可能是因为磁盘已满或者发生了错误。 5. fseek函数原型: ```c int fseek(FILE *stream, long offset, int whence); ``` 使用说明: - stream:打开文件的指针。 - offset:偏移量,可以是正数或负数,如果是负数则表示向文件开头偏移。 - whence:偏移的位置,可以是 `SEEK_SET`(文件开头)、`SEEK_CUR`(当前位置)、`SEEK_END`(文件结尾)。 返回值: - 执行成功返回 0。 - 执行失败返回非 0 值。 使用注意事项: - 在使用文件 I/O 函数时,需要先打开文件,处理完后再关闭文件。 - 在使用 fread fwrite 函数时,需要注意缓冲区的大小,避免溢出。 - 在使用 fseek 函数时,需要注意偏移量的取值范围,避免越界访问文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值