电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
C文件操作2:如何随机的进行文件读取?
分 享
扫描二维码分享
C文件操作2:如何随机的进行文件读取?
C语言
文件操作
码农爱学习
关注
发布时间: 2021-06-03
丨
阅读: 284
上篇介绍了C语言文件操作的基本函数,fopen、fwrite、fread、fclose。这些只能从文件头读写或文件尾追加写入。 本篇介绍文件中随机位置读写的方法,会介绍fseek、ftell、rewind。 此外,再介绍几个字符读写函数:fputs、fgets、fpritf、fscanf,用于编写测试代码时用。 # 文件随机位置读写基础函数 对于文件的随机位置读写,可以通过 fseek 、ftell与rewind 函数来完成 ## fseek > fseek用于设置流stream的文件读写位置为给定的偏移 > > seeK的中文含义是“寻找” 函数原型: ```c /@@** @func: fseek * @brief: 设置流stream的文件读写位置为给定的偏移 * @para: [fp]:文件指针 * [offset]:偏移量,表示移动的字节数,正数表示正向(结尾)偏移,负数表示负向(开头)偏移 * [from]:表示设定从文件的哪里开始偏移,取值范围如下表所示 * @return:执行成功,返回0 (fp将指向以from为基准,偏移offset个字节的位置) * 执行失败,返回值-1,并设置errno的值。比如offset超过文件自身大小,则不改变fp指向的位置 */ int fseek(FILE *fp,long offset,int from); ``` **from参数的取值** | 起始点 | 表示 符号 | 数字表示 | | -------- | --------- | -------- | | 文件开头 | SEEK_SET | 0 | | 当前位置 | SEEK_CUR | 1 | | 文件末尾 | SEEK_END | 2 | 例如: - 将读写位置移动到文件**开头** ```c fseek(fp, 0L, SEEK_SET) ``` - 将读写位置移动到文件**末尾** ```c fseek(fp,0L,SEEK_END); ``` - 将读写位置移动到**离文件开头100字节**处 ```c fseek(fp,100L,SEEK_SET); ``` - 将读写位置移动到**离文件当前位置100字节**处 ```c fseek(fp,100L,SEEK_CUR); ``` - 将读写位置退回到**离文件结尾100字节**处(offset为负数表示向开头处移动) ```c fseek(fp,-100L,SEEK_END); ``` > 注意: > > fseek 函数一般用于二进制文件,当然也可以用于文本文件。 > > **当fseek函数操作文本文件时,要注意回车换行的情况**。 > > 因为在一般浏览工具(如 UltraEdit)中,回车换行被视为两个字符 0x0D 和 0x0A,但真实的文件读写和定位却按照一个字符 0x0A 进行处理。 > > 这种清空,可以先将文件整个读入内存,然后在内存中手工插入 0x0D。 ## ftell > fseek 函数只返回执行的结果是否成功,并不返回文件的读写位置 > > 获取当前文件的读写位置,还需要使用 ftell 函数来获取 函数原型: ```c /@@** @func: ftell * @brief: 得到文件当前的位置指针相对于文件首的偏移字节数 * @para: [fp]:文件指针 * @return: */ long ftell(FILE *fp); ``` fell的主要作用就是获取当前的读写位置,在随机方式存取文件时,由于文件位置频繁前后移动,程序不容易确定文件的当前位置。 在使用 fseek 函数移动了位置后,再调用函数 ftell 就能非常容易地确定文件的当前位置。 **fell的一个小应用:获取文件的长度** 加入一共文件的读写位置已经被移动了多次,这时若想获得文件的长度,可以向用ftell记录当前的读写位置,然后将其移动到末尾,再利用ftell获取文件尾至头部的位置,就是文件的长度了。获取程度之后,再将读写位置使用fseek复原即可。 ```c long getFileLength(FILE *fp) { long curPos=0L;/@@*文件当前的位置指针位置*/ long len=0L; curPos = ftell(fp);/@@*记录文件当前的位置指针的位置*/ fseek(fp, 0L, SEEK_END);/@@*读写位置移动到文件末尾*/ len = ftell(fp);/@@*获取文件末尾到文件开头的长度*/ fseek(fp, curPos, SEEK_SET);/@@*再将读写位置移回到之前的位置*/ return len; } ``` 代码对应的设计思路如下图: ![](https://cf04.ickimg.com/bbsimages/202105/756f18c3e74a6c0479bf2f5eab3d1959.png) ## rewind > rewind的中文意思是“倒回” > > rewind 函数用于将文件内部的位置指针重新指向一个流(数据流或者文件)的起始位置。 > > 注意,这里的“指针”表示的不是文件指针,而是**文件内部的位置指针**。即随着对文件的读写,文件的位置指针(指向当前读写字节)向后移动。而文件指针指向整个文件,如果不重新赋值,文件指针不会发生改变。 函数原型: ```c /@@** @func: rewind * @brief: 将文件内部的位置指针重新指向一个流(数据流或者文件)的起始位置 * @para: [fp]:文件指针 * @return:无 */ void rewind(FILE *fp); ``` > 由于 rewind 函数没有返回值,所以很难判断`rewind(fp)`是否执行成功。 > > 因此,应该尽量使用 fseek 来替换 rewind 函数,从而以验证流已经成功地回绕 下面,再介绍几个字符读写函数:fputs、fgets、fpritf、fscanf,用于编写测试代码时用。 # 文件读取写入字符串 ## fputs > fputs函数用于将一行字符串写入文件 函数原型: ```c /@@** @func: fputs * @brief: 将一行字符串写入文件 * @para: [str]:要写入的字符串 * [fp]:文件指针 * @return:写入成功,返回非负数 * 写入失败,返回EOF */ int fputs( char *str, FILE *fp ); ``` ## fgets > fgets 函数用来从指定的文件中读取一个字符串,并保存到字符数组中 函数原型: ```c /@@** @func: fgets * @brief: 从指定的文件中读取一个字符串,并保存到字符数组中 * @para: [str]:字符数组 * [n]:要读取的字符数目 * [fp]:文件指针 * @return:读取成功,返回字符数组首地址,也即str * 读取失败,返回 NULL */ char *fgets ( char *str, int n, FILE *fp ); ``` ## fprintf 函数原型: ```c /@@** @func: fprintf * @brief: 将格式化的字符串写入文件 * @para: [fp]:文件指针 * [format]:格式化字符串,要被写入到fp中的文本 * @return:写入成功,返回写入的字符数 * 写入失败,返回负数 */ int fprintf(FILE *fp, const char *format, ...) ``` 使用方法: ```c FILE *fp = fopen ("test.txt", "w+"); char *str = "xxpcb.gitee.io"; int num = 666; fprintf(fp, "%s %d", str, num); fclose(fp); ``` ## fscanf 函数原型: ```c /@@** @func: fscanf * @brief: 从文件中读取格式化的字符串 * @para: [fp]:文件指针 * [format]:格式化字符串,从fp中读出的内容 * @return:读取成功,返回读出的字符数 * 读取失败,返回负数 */ int fscanf(FILE *fp, const char *format, ...) ``` 使用方法: ```c FILE *fp = fopen ("test.txt", "r"); char str[64] int num; fscanf(fp, "%s %d", str, num); fclose(fp); ``` # 使用示例 下面的测试程序,首先使用fputs函数写入了一段字符串“Hello world”,然后使用fseek函数,将读写位置移动到了文件开头向后的第6个字符,接着在该处,又使用fputs函数写入了一段字符串“xxpcb.github.io”,这样,就会在指定位置处,进行覆盖写入。最后,使用fgets函数,将文件中写入的内容再获取出来。 ```c #include
#define N 100 int main () { /@@*打开*/ FILE *fp = fopen("../test-futs.txt","wt+");/@@*打开一个文件*/ if(NULL == fp) { printf("open file fail\r\n"); goto end; } /@@*写入*/ fputs("hello world\n", fp);/@@*先写入一段信息*/ fseek( fp, 6, SEEK_SET );/@@*读写位置从开头向后移动6个位置*/ fputs("xxpcb.github.io\n", fp);/@@*再写入一段信息*/ if(0 != fputs("码农爱学习\n", fp));/@@*再写入一段信息*/ { printf("fputs file ok\r\n"); } /@@*关闭*/ fclose(fp); /@@*再打开*/ fp = fopen("../test-futs.txt","rt"); if(NULL == fp) { printf("open file fail\r\n"); goto end; } /@@*读取*/ printf("fgets file ...\r\n"); char str[N+1]; int line = 0; while(fgets(str, N, fp) != NULL)/@@*使用while, 可以一行一行的获取*/ { printf("[%d]:%s", ++line, str); } end: return(0); } ``` 代码对应的设计思路如下图: ![](https://cf04.ickimg.com/bbsimages/202105/98ba08c670ae9deb91fcf013c1af80d8.png) 附:本篇以及上篇的测试代码,可从我的gitee仓库获取 地址:https://gitee.com/xxpcb/c-test/tree/master/C-file-operate
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
码农爱学习
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交