新闻  |   论坛  |   博客  |   在线研讨会
Linux库函数之文件操作fopen/fread/fwrite/fclose/fgets/ftell/fseek...
电子禅石 | 2020-03-12 13:46:04    阅读:2026   发布文章

  Linux应用层软件的开发,总会涉及到文件(如:日志,配置)的操作,开发那段时间相关库函数用的比较多,当然
就能随手写出来,但是考虑到人的记忆是有时间限制的,加上现如今海量信息涌入大脑,有段时间不使用就会忘记,这次
趁着手头开发涉及到比较多这方面的知识,决定花点时间写给将来自己看,以后有疑问直接查看记录就OK啦,不用每次都
找度娘,废话不多说,切入正题。
主要介绍文件操作常用的库函数:
1)fopen函数
头文件:#include <stdio.h>
函数原型:FILE *fopen(const char *path, const char *mode);
参数:
path:可能的值:常量字符串(如:“/home/dir/test.txt”),字符串指针(如:char *p_file = "/home/dir/test.txt";),
当然数组也行(如:char file[100] = {"/home/dir/test.txt"};)
mode:可选参数有“r”   "w"   "a"   "r+"   "w+"   "a+"  “其他选项+b”
"r":Open text file for reading.  The stream is positioned at the beginning of the file. 
该文件必须存在,否则失败;像获取日志内容,就用可以只读方式打开文件,从文件开始读取数据;
"w":Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.
文件存在清空,文件不存在则创建;这个就要注意若是要向日志中不断添加新的内容就不能改模式打开啦;
"a":Open  for  appending (writing at end of file).  The file is created if it does not exist.
The stream is positioned at the end of the file.
文件不存在则创建,文件存在则打开不清空,指向文件尾部,不断向日志写内容一般用该方式,不覆盖原内容;
“b”:则是以文件存储时的二进制方式打开文件,若是不添加"b"则是以文本方式(ASCII码)方式打开,这个主要
看实际情况来定,文件一般分为文本文件和二进制文件,文本文件在磁盘存放时每个字符对应一个字节,而二进制
文件则是按照二进制编码规则来存储,简单例子:文本文件的5678对应存储为 00110101 00110110 00110111 00111000
二进制存储为:00010110 00101110,一般实际应用中我们编辑的都是文本文件,二进制文件也有例如打开一张图片等。
根据man手册的描述总结:
a)若是需要对一个已经存在并且有内容的文件操作,仅仅读取文件内容推荐"r"模式或者“r+”可以有写的权限;
b)若是需要创建一个新的文件,一般“w”模式或者"w+"有读的权限,可以读取写入的内容;
c)若是在一个已经存在的文件基础上,继续在文件尾部添加内容,则可以"a"模式或者“a+”有读的权限;
d)若是操作二进制文件则是需要在模式中添加"b"。
返回值:成功打开文件返回FILE指针(文件流),失败返回NULL;一般会判断该返回值再执行后续任务;
2)fclose函数
头文件:#include <stdio.h>
    函数原型:int fclose(FILE *fp);
参数:
fp:成功打开文件返回的FILE指针
功能主要是关闭该文件流,释放指针;
返回值:成功返回0,失败EOF   (-1);一般很少做判断;
3)fread函数
头文件:#include <stdio.h>
函数原型:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
ptr:用来存储文件内容开辟的内存空间指针或说地址,可以是数组名或者指向malloc分配的内存的指针;
size:读取的块个数,跟nmemb配合使用;size为1,表示读取一个大小为nmemb的文件内容到ptr指向内存中;
nmemb:一次读取的文件内容大小,一般是ptr指向的内存大小,当然前提是size为1;
stream:就是fopen打开文件返回值;
返回值:成功返回读取内容的大小,在size为1时一般小于等于nmemb值,失败或者文件末尾返回0。
4)fwrite函数
头文件:#include <stdio.h>
函数原型:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:
ptr:待写内容的地址;
size:写入的块个数,跟nmemb配合使用;size为1,表示写入一个大小为nmemb的内容到文件中;
nmemb:一次写入文件的内容大小,一般是ptr指向的内存大小,当然前提是size为1;
stream:就是fopen打开文件返回值;
返回值:成功返回写入内容的大小,失败或者文件末尾返回0。
5)fgets函数
头文件:#include <stdio.h>
函数原型:char *fgets(char *s, int size, FILE *stream);
参数:
s:用于存储文件内容的地址;
size:从文件中获取内容的大小,可以自行根据实际情况定义,若是按行读取一般定义为1024字节;
stream:就是fopen打开文件返回值;
功能:这个函数用处很大,尤其是在读取配置文件时的应用,一般用来按行读取文件内容,然后分析
每行的内容,这里面就会涉及到字符串的匹配或者提取字段等等,那么读取时会有些什么需要注意的呢?
情况一:当读取的内容小于size值时,机会把所有的字符全部读入到s中包括‘\r\n’,最后自动加上‘\0’构成
一个完整的字符串,这个时候就会需要添加代码过滤掉'\r\n',将其修改为‘\0’;
情况二:当读取的内容大于size,那么就会自动截断,最后一位为'\0'构成一个完整字符串;
该函数的使用主要注意这两点,也可以从键盘读取输入stdin。
返回值:成功返回s,失败返回NULL。
6)ftell函数
头文件:#include <stdio.h>
函数原型:long ftell(FILE *stream);
该函数主要用来获取当前文件光标(指针)所处的位置离文件首部之间的字节大小;用的不是太多,但是
配合fseek或者以‘a’方式打开文件,可以获取文件大小;
返回值:成功返回大小,失败返回0。
7)fseek函数
头文件:#include <stdio.h>
函数原型:int fseek(FILE *stream, long offset, int whence);
参数:
offset:偏移量,nL,n>0表示whence指定位置正向偏移,白话说就是从whence往文件尾方向,n<0则是
表示whence指定位置反向偏移,白话说就是从whence往文件头方向,n = 0就是whence当前位置;
whence:有三个选项:SEEK_SET(文件首部)/SEET_CUR(当前位置)/SEEK_END(文件末尾)
这个函数用的也比较少,可以配合ftell获取某段内容的大小,一般会涉及到关键字定位等;
目前就总结这么多,至于具体每个的实现,那就是写代码调试的事情了,这里就不在贴代码,一个是网上有许多
二是没太多时间,主要还是方法对头,其他的都好说,只是时间问题,问题方法想清楚了在动手,事半功倍。
努力提升中..........
————————————————
1、FILE *fopen(char *path,*mode);
mode:
r:  读打开, 不创建
w: 写打开,创建/清空
a: 写打开, 创建/追加
r+: 读/写打开,不创建
w+:读/写打开,创建/清空
a+:读/写打开, 创建/追加
 衍生:
rb,rb+,wb,wb+,ab,ab+;  对二进制操作
rt,rt+,wt,wt+,at,at+;         对文本文件操作
2、例程说明:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define filelen 10
int main()
{
    int ret,i;
    FILE * fp = fopen("test","w+");      //读/写打开,创建/清空
    char buf_w[filelen] = {"HeLlow!"};
    for(i=0;i<filelen;i++)
    {
        printf("[%d] %c ",i,buf_w[i]);
    }
//打印    [0] H [1] e [2] L [3] l [4] o [5] w [6] ! [7]  [8]  [9]
    char buf_r[filelen];
    ret = fwrite(buf_w,sizeof(char),filelen,fp);  //此时文件指针已经到了文件尾部
    printf("fwrit: %d\n",ret);
   
    rewind(fp);       //将文件指针置于文件头部
    memset(buf_r,0,sizeof(buf_r));
    ret = fread(buf_r,sizeof(char),filelen,fp);  //此时文件指针再次到了尾部
    printf("fread: %d\n",ret);
    for(i=0;i<filelen;i++)
    {
        printf("[%d] %c ",i,buf_r[i]);
    }
//打印    [0] H [1] e [2] L [3] l [4] o [5] w [6] ! [7]  [8]  [9] 
    ret = fseek(fp,0,SEEK_SET);          //将文件指针置于距离 头部 偏移量 为 0 的位置,等同于rewind()
    memset(buf_r,0,sizeof(buf_r));
    ret = fread(buf_r,sizeof(char),filelen,fp);   //文件指针到达文件尾部
    printf("1 ret:%d  buf_r[0]:%c\n",ret,buf_r[0]);
//打印 1 ret:10  buf_r[0]:H
    fseek(fp,-4,SEEK_CUR);                      //文件指针尾部向前偏移 4
    memset(buf_r,0,sizeof(buf_r));
    ret = fread(buf_r,sizeof(char),filelen,fp);  //文件指针到达文件尾部
    printf("2 ret:%d buf_r[0]:%c\n",ret,buf_r[0]);
//打印  2 ret:4 buf_r[0]:!
    fseek(fp,0,SEEK_END);                         //文件指针置于尾部
    memset(buf_r,0,sizeof(buf_r));
    ret = fread(buf_r,sizeof(char),filelen,fp);
    printf("3 ret:%d buf_r[0]:%c\n",ret,buf_r[0]);
//打印 3 ret:0 buf_r[0]:
    ret = ftell(fp);                                           //从文件开始到当前位置的偏移值,与fseek(fp,0,SEEK_END)配合,计算文件的大小。 
    printf("4 ret:%d\n",ret); // 打印 4 ret:10

    fclose(fp);
    return 0;
}

程序运行结果:
[0] H [1] e [2] L [3] l [4] o [5] w [6] ! [7]  [8]  [9]  
fwrit: 10
fread: 10
[0] H [1] e [2] L [3] l [4] o [5] w [6] ! [7]  [8]  [9]  
1 ret:10  buf_r[0]:H
2 ret:4 buf_r[0]:!
3 ret:0 buf_r[0]:
4 ret:10
————————————————
版权声明:本文为CSDN博主「嗜血之心」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wj8987922/article/details/52216813
原文链接:https://blog.csdn.net/donghanhang/article/details/51166793


*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
属于自己的技术积累分享,成为嵌入式系统研发高手。
推荐文章
最近访客