C语言文件操作之fread函数详解
作者:韩曙亮 发布时间:2023-07-06 18:24:15
前言
二进制文件读写两个重要的函数 , fread 和 fwrite , fread 用于读取文件 , fwrite 用于写出文件 ;
fread / fwrite 函数 既可以操作 二进制文件 , 又可以操作 文本文件 ;
getc / putc 函数 , fscanf / fprintf 函数 , fgets / fgets 函数 , 只能用于操作 文本文件 ;
一、fread 函数
fread 函数作用 : 从文件中读取若干字节数据到内存缓冲区中 ;
fread 函数原型 :
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
void *buffer 参数 : 将文件中的二进制数据读取到该缓冲区中 ;
size_t size 参数 : 读取的 基本单元 字节大小 , 单位是字节 , 一般是 buffer 缓冲的单位大小 ;
如果 buffer 缓冲区是 char 数组 , 则该参数的值是 sizeof(char) ;
如果 buffer 缓冲区是 int 数组 , 则该参数的值是 sizeof(int) ;
size_t count 参数 : 读取的 基本单元 个数 ;
FILE *stream 参数 : 文件指针 ;
size_t 返回值 : 实际从文件中读取的 基本单元 个数 ; 读取的字节数是 基本单元数 * 基本单元字节大小 ;
代码示例 : 一次性读满整个缓冲区 ;
#include <stdio.h>
int main()
{
// 使用 "rb" 读取二进制方式打开文件
FILE *p = fopen("D:\\a.txt", "rb");
// 用于接收读取数据的缓冲区
char buffer[1024] = {0};
// buffer : 将文件读取到内存的位置
// sizeof(char) : 读取的基本单元字节长度
// sizeof(buffer) : 读取的基本单元个数,
// 读取字节个数是 sizeof(buffer) * sizeof(char)
// p : 文件指针
fread(buffer, sizeof(char), sizeof(buffer), p);
// 打印读取的内容
printf("buffer = %s\n", buffer);
printf("Main End\n");
return 0;
}
执行结果 :
二、缓冲区受限的情况 ( 循环读取文件 | feof 函数判定文件读取完毕 )
假设缓冲区很小 , 文件很大 , 则需要循环读取文件数据 ;
使用 feof(p)
判定文件是否读取完毕 , 如果返回 true 说明文件没有读取完毕 , 返回 false , 说明文件读取完毕 ;
代码示例 :
#include <stdio.h>
int main()
{
// 使用 "rb" 读取二进制方式打开文件
FILE *p = fopen("D:\\a.txt", "rb");
// 用于接收读取数据的缓冲区
char buffer[4] = {0};
while(!feof(p)){
memset(buffer, 0, sizeof(buffer));
// buffer : 将文件读取到内存的位置
// sizeof(char) : 读取的基本单元字节长度
// sizeof(buffer) : 读取的基本单元个数,
// 读取字节个数是 sizeof(buffer) * sizeof(char)
// p : 文件指针
fread(buffer, sizeof(char), sizeof(buffer), p);
// 打印读取的内容
printf("buffer = %s\n", buffer);
}
printf("Main End\n");
return 0;
}
执行结果 : 读取之后出现乱码 , 这是由于每次读取 10 10 10 字节 , 但是字符串必须要以 ‘\0’ 进行结尾 , 如果没有 ‘\0’ 则会一直读取直到出现 ‘\0’ 字符串结尾位置 ;
三、处理乱码问题
为了避免上述打印出现乱码的情况 , char buffer[4] = {0};
准备了 4 4 4 字节缓冲区 , 每次只使用其中的 3 3 3 个字节 , 这就能保证最后一个字节必定是 ‘\0’ , 打印时就不会出现乱码 ;
代码示例 :
#include <stdio.h>
int main()
{
// 使用 "rb" 读取二进制方式打开文件
FILE *p = fopen("D:\\a.txt", "rb");
// 用于接收读取数据的缓冲区
char buffer[4] = {0};
while(!feof(p)){
memset(buffer, 0, sizeof(buffer));
// buffer : 将文件读取到内存的位置
// sizeof(char) : 读取的基本单元字节长度
// sizeof(buffer) : 读取的基本单元个数,
// 读取字节个数是 sizeof(buffer) * sizeof(char)
// p : 文件指针
fread(buffer, sizeof(char), sizeof(buffer) - 1, p);
// 打印读取的内容
printf("buffer = %s\n", buffer);
}
printf("Main End\n");
return 0;
}
执行结果 : 每次从文件中读取 缓冲区字节数 - 1 个字节 , 则能完整的将文本打印出来 ;
四、记录读取的字节个数
fread 函数返回值表示读取到的 基本单元 的个数 , 如果设置了 1KB 的缓冲区 , 但是文件中只有 5 字节 , 则 fread 的返回值就是实际读取到的数据个数 ;
代码示例 :
#include <stdio.h>
int main()
{
// 使用 "rb" 读取二进制方式打开文件
FILE *p = fopen("D:\\a.txt", "rb");
// 用于接收读取数据的缓冲区
char buffer[1024] = {0};
// buffer : 将文件读取到内存的位置
// sizeof(char) : 读取的基本单元字节长度
// sizeof(buffer) : 读取的基本单元个数,
// 读取字节个数是 sizeof(buffer) * sizeof(char)
// p : 文件指针
// 返回值 : fread 函数返回值表示读取到的 基本单元 的个数
size_t count = fread(buffer, sizeof(char), sizeof(buffer) - 1, p);
// 打印读取的内容
printf("buffer = %s , read count = %u\n", buffer, count);
printf("Main End\n");
return 0;
}
执行结果 :
五、读取到 0 字节的情况
如果 基本单元 大小 4 4 4 字节 , 文件中只有 3 3 3 字节数据 , 则使用 fread 函数读取文件 , 缓冲区设置 1KB , 则实际读取到的基本单元个数是 0 0 0 ;
代码示例 :
#include <stdio.h>
int main()
{
// 使用 "rb" 读取二进制方式打开文件
FILE *p = fopen("D:\\a.txt", "rb");
// 用于接收读取数据的缓冲区
char buffer[1024] = {0};
// buffer : 将文件读取到内存的位置
// sizeof(char) : 读取的基本单元字节长度
// sizeof(buffer) : 读取的基本单元个数,
// 读取字节个数是 sizeof(buffer) * sizeof(char)
// p : 文件指针
// 返回值 : fread 函数返回值表示读取到的 基本单元 的个数
size_t count = fread(buffer, sizeof(int), sizeof(buffer) - 1, p);
// 打印读取的内容
printf("buffer = %s , read count = %u\n", buffer, count);
printf("Main End\n");
return 0;
}
执行结果 :
六、读取完毕的情况
如果文件已经读取完毕 , 不关闭文件 , 再次调用 fread 函数继续读取 , 则读取到的 基本单元 个数是 0 0 0 ;
使用 feof(p)
判定文件是否读取完毕 , 如果返回 true 说明文件没有读取完毕 , 返回 false , 说明文件读取完毕 ;
代码示例 :
#include <stdio.h>
int main()
{
// 使用 "rb" 读取二进制方式打开文件
FILE *p = fopen("D:\\a.txt", "rb");
// 用于接收读取数据的缓冲区
char buffer[1024] = {0};
// buffer : 将文件读取到内存的位置
// sizeof(char) : 读取的基本单元字节长度
// sizeof(buffer) : 读取的基本单元个数,
// 读取字节个数是 sizeof(buffer) * sizeof(char)
// p : 文件指针
// 返回值 : fread 函数返回值表示读取到的 基本单元 的个数
size_t count = fread(buffer, sizeof(char), sizeof(buffer) - 1, p);
// 打印第一次读取的内容
printf("First fread : buffer = %s , read count = %u\n", buffer, count);
count = fread(buffer, sizeof(int), sizeof(buffer) - 1, p);
// 打印第二次读取的内容
printf("Second fread : buffer = %s , read count = %u\n", buffer, count);
printf("Main End\n");
return 0;
}
执行结果 :
七、读取文本文件 “\n” 与 读取二进制文件 “\r\n” 区别
以下区别只在 Windows 系统存在 , 在 Linux / Unix 中读取文本数据与二进制数据没有区别 ;
使用 ‘rb’ 方式打开文件 , 读取二进制文件 , 然后调用 fread 函数读取文件 ,
#include <stdio.h>
int main()
{
// 使用 "rb" 读取二进制方式打开文件
FILE *p = fopen("D:\\a.txt", "rb");
// 用于接收读取数据的缓冲区
char buffer[1024] = {0};
// buffer : 将文件读取到内存的位置
// sizeof(char) : 读取的基本单元字节长度
// sizeof(buffer) : 读取的基本单元个数,
// 读取字节个数是 sizeof(buffer) * sizeof(char)
// p : 文件指针
// 返回值 : fread 函数返回值表示读取到的 基本单元 的个数
size_t count = fread(buffer, sizeof(char), sizeof(buffer) - 1, p);
// 打印第一次读取的内容
printf("fread : buffer = %s , read count = %u\n", buffer, count);
// 逐个字节打印读取出数据的 ASCII 码
int i = 0;
for(i = 0; i < count; i ++){
printf("buffer[%d] = %x\n", i, buffer[i]);
}
printf("Main End\n");
return 0;
}
执行结果 : 第 2 2 2 个索引读取出来的值是 0xd 对应 ‘\r’ , 第 3 3 3 个值是 0xa 对应 ‘\n’ ;
注意 : 最后两个字节是空行对应的 “\r\n” ;
fread : buffer = ab
cd
, read count = 8
buffer[0] = 61
buffer[1] = 62
buffer[2] = d
buffer[3] = a
buffer[4] = 63
buffer[5] = 64
buffer[6] = d
buffer[7] = a
Main End
使用 ‘r’ 方式打开文件 , 读取文本文件 , 然后调用 fread 函数读取文件 ,
#include <stdio.h>
int main()
{
// 使用 "rb" 读取二进制方式打开文件
FILE *p = fopen("D:\\a.txt", "r");
// 用于接收读取数据的缓冲区
char buffer[1024] = {0};
// buffer : 将文件读取到内存的位置
// sizeof(char) : 读取的基本单元字节长度
// sizeof(buffer) : 读取的基本单元个数,
// 读取字节个数是 sizeof(buffer) * sizeof(char)
// p : 文件指针
// 返回值 : fread 函数返回值表示读取到的 基本单元 的个数
size_t count = fread(buffer, sizeof(char), sizeof(buffer) - 1, p);
// 打印第一次读取的内容
printf("fread : buffer = %s , read count = %u\n", buffer, count);
// 逐个字节打印读取出数据的 ASCII 码
int i = 0;
for(i = 0; i < count; i ++){
printf("buffer[%d] = %x\n", i, buffer[i]);
}
printf("Main End\n");
return 0;
}
执行结果 : 第 2 2 2 个索引读取出来的值是 0xa 对应 ‘\n’ ;
最后的空行只有一个 ‘\n’ ;
fread : buffer = ab
cd
, read count = 6
buffer[0] = 61
buffer[1] = 62
buffer[2] = a
buffer[3] = 63
buffer[4] = 64
buffer[5] = a
Main End
来源:https://blog.csdn.net/shulianghan/article/details/117338844
猜你喜欢
- 可以静态绑定数据源,这样就自动为DataGridView控件添加 相应的行。假如需要动态为DataGridView控件添加新行,方法有很多种
- 接收到这样一个需求,就是英文名字中firstName和lastName,其中任何一个为null,就返回Empty。刚拿到需求,这不简单,if
- 1.引言在开发中,拖放是一种比较常见的手势操作,使用它能够让应用的交互更加地便捷和友好,本文将简要介绍如何为Android中的View添加拖
- @RequestMapping注解注意点类上加没加@RequestMappin注解区别1.如果类上加了 @RequestMappin注解,那
- 1. strlen —— 求字符串长度1.1 strlen 的声明与用处strlen ,我们有一些英
- 本文实例为大家分享了Struts2框架拦截 器实例的示例代码,供大家参考,具体内容如下在看拦截 器的小例子的前我们先来看看sturts2的原
- 本文实例讲述了java实现的简单猜数字游戏代码。分享给大家供大家参考。具体代码如下:import java.util.InputMismat
- 一、Flutter代码的启动起点我们在多数的业务场景下,使用的都是FlutterActivity、FlutterFragment。在在背后,
- 您已经看到很多包含视频内容的应用程序,比如带有视频教程的食谱应用程序、电影应用程序和体育相关的应用程序。您是否想知道如何将视频内容添加到您的
- Android Build类的详解及简单实例一、类结构:java.lang.Object? android.os.Build二、类概述:从系
- [LeetCode] 3. Longest Substring Without Repeating Characters 最长无重复字符的子
- google benchmark已经为我们提供了类似的功能,而且使用相当简单。具体的解释在后面,我们先来看几个例子,我们人为制造几个时间复杂
- 在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较
- 已知两个链表list1和list,2,各自非降序排列,将它们合并成另外一个链表list3,并且依然有序,要求保留所有节点。实现过程中,lis
- 使用AS创建ADIL文件时AS会在main文件夹下给我们生成一个aidl文件夹和一个相同包名的包,通常我们会把所有和ADIL相关的类或文件放
- 本文实例为大家分享了android自定义环形对比图的具体代码,供大家参考,具体内容如下1.首先在res/values里创建一个attr.xm
- 已知字符串“aabbbcddddeeffffghijklmnopqrst”编程找出出现最多的字符和次数,要求时间复杂度小于O(n^2)/**
- Android中获取资源 id 及资源 id 的动态获取我们平时获取资源是通过 findViewById 方法进行的,比如我们常
- 相比于直线检测,直线拟合的最大特点是将所有数据只拟合出一条直线void fitLine( InputArray points, Output
- 最近“全网域(Web Scale)”一词被炒得火热,人们也正在通过扩展他们的应用程序架构来使他们的系统变得更加“全网域”。但是究竟什么是全网