文章目录

  • 一、文件操作基础概念
  • 二、文件读写:按照字符方式读写
  • 三、文件读写:按行和块读写
  • 四、文件读写:格式化和随机位置

一、文件操作基础概念

C语言中的文件操作的好处:
      一个文件通常是再磁盘上一段命名的存储区,但是对于操作系统来说,文件就会复杂一些。例如,一个大文件可以存储在一些分散的区段中,或者还会包含一些操作系统可以确定其文件类型的附加数据,但是这些是操作系统需要关心的事,而不是我们需要关系心的事情,我们只需要考虑如何在C程序中处理文件,调用接口实现文件操作,不需要关心底层如何实现,省去了许多麻烦

文本流与二进制流区别:
文本流: 即是我们常说的以文本模式读取文件。文本流的有些特性在不同的操作系统中可能不同,Windows系统中,文本文件约定以一个回车符和一个换行符结尾,但是在Linux下只使用一个换行符结尾。
二进制流: 二进制流中的字节将完全根据程序编写它们的形式写入到文件中,而且完全根据它们从文件或设备读取的形式读入到程序中,未做任何改变。这种类型的流适用于非文本数据。
      C语言在处理这两种文件时候并不区分,都看成是字符流,按字节进行处理。我们经常看到的文本方式打开文件和二进制方式打开文件仅仅体现在换行符的处理上:Windows下,文件的换行符是\r\n,而在Linux下换行符则是\n。

文件操作:
1.程序为同时处于活动状态的每个文件声明一个指针变量,其类型为FILE * 。这个指针指向这个FILE结构,当它处于活动状态时由流使用。
2.流通过fopen函数打开。为了打开一个流,我们必须指定需要访问的文件或设备以它们的访问方式(读、写或者读写)。Fopen和操作系统验证文件或者设备是否存在并初始化FILE。
3.根据需要对文件进行读写操作。
4.最后调用fclose函数关闭流。关闭一个流可以防止与它相关的文件被再次访问。保证任何存储于缓冲区中的数据被正确写入到文件中,并且释放FILE结构。
       标准I/O更为简单,因为它们并不需要打开或者关闭。I/O函数以三种基本的形式处理数据:单个字符、文本行和二进制数据。

文件指针: 文件是由操作系统管理的单元,当我们想操作一个文件的时候,让操作系统帮我们打开文件,操作系统把我们指定要打开的文件的信息保存起来,并且返回给我们一个指针指向文件的信息。文件指针也可以理解为代打开的文件,这个指针的类型为FILE类型,定义在stdio.h头文件中,通过文件指针,我们就可以对文件进行各种操作。 对每一个C程序,运行时系统必须提供至少三个流:标准输入、标准输出、标准错误,它们都是一个指向FILE结构的指针。

该指针本质上为一个结构体:如下

struct _iobuf
{char *_ptr;//文件输入的下一个位置int _cnt;//剩余多少字符未被读取char *_base;//基础位置(起始位置)int _flag;//文件标志,当读到文件尾时该标志变为真1,否则还是0int _file;//文件的有效性验证int _charbuf;//检查缓冲区状况,如果无缓冲区则不读取int _bufsiz;//文件的大小char *_tmpfname;//临时文件名
};
typedef struct _iobuf FILE;

文件缓冲区作用: 我们从磁盘里取信息,先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度

有缓冲区好处:
1.提高硬件的寿命。
2.提高了读写效率。

二、文件读写:按照字符方式读写

文件打开(fopen):表示将用户指定的文件在内存分配一个FILE结构区,并将该结构的指针返回给用户程序,以后用户程序就可用此FILE指针来实现对指定文件的存取操作了。

函数原型:FILE* fopen(const char* filename,const char* mode);
函数功能:打开文件
函数参数:
filename:需要打开的文件名,根据需要加上路径;
node:打开文件的权限设置;
函数返回值:
成功:文件指针;
失败:NULL;

打开文件的方式:

方式 含义
“r” 打开,只读,文件必须已经存在
“w” 只写,如果文件不存在则创建,如果已存在则把文件长度截断为0字节。再重新写,也就是替换掉原来的文件内容文件指针指到头
“a” 只能在文件末尾追加数据,如果文件不存在则创建
“rb” 打开一个二进制文件,只读
“wb” 打开一个二进制文件,只写
“ab” 打开一个二进制文件,追加
“r+” 允许读和写,文件必须已经存在
“w+” 允许读和写,文件不存在则创建,如果文件已存在则把文件长度截断为0字节再重新写
“a+” 允许读和追加数据,如果文件不存在则创建
“rb+” 以读/写方式打开一个二进制文件
“wb+” 以读/写方式建立一个新的二进制文件
“ab+” 以读/写方式打开一个二进制文件进行追加

文件关闭(fclose):文件操作完成后,如果程序没有结束,必须要用fclose()函数进行关闭。 是因为对打开的文件进行写入时,若文件缓冲区的空间未被写入的内容填满,这些内容不会写道打开的文件中,只有对打开的文件进行关闭操作时,停留在文件缓冲区的内容才能写到该文件中去,从而使文件完整。再而一旦关闭文件,该文件对应的FILE结构将被释放,从而使关闭的文件的到保护,因为此时对该文件的存取操作不会进行,文件的关闭也意味着释放了该文件的缓冲区。

函数原型:int fclose(FILE* stream);
函数功能:关闭fopen()之前打开的文件。让缓冲区的数据写入文件中,并释放系统所提供的文件资源。
函数参数:
stream:文件指针。
函数返回值:
成功:0;
失败:-1;

文件读写函数:
1.按照字符写文件:fputc();

函数原型:int fputc(int char, FILE *stream);
函数功能:按照字符写文件
函数参数:
char:这是要被写入的字符。该字符以其对应的int值进行传递。
stream:这是指向FILE对象的指针,该FILE对象标识了要被写入字符的流。
函数返回值:
成功:返回被写入的字符。
失败:返回EOF,并设置错误标识符。
void test()
{FILE* f_write = fopen("./1.txt","w");//当前目录下写文件if (f_write == NULL){return;}char buf[] = "hello world";for (int i=0; i<strlen(buf); i++){fputc(buf[i],f_write);//写入}fclose(f_write);
}

打开当前目录:写入成功。

2.按照字符读文件:fgetc();

函数原型:int fgetc(FILE *stream);
函数功能:按照字符读文件
函数参数:
stream:指向FILE对象的指针,该FILE对象标识了要在上面执行操作的流
函数返回值:
成功:以无符号char强制转换为int的形式返回读取的字符
失败:返回EOF
void test()
{FILE* f_read = fopen("./1.txt","r");//当前目录下读文件if (f_read == NULL){return;}char ch;while ((ch = fgetc(f_read)) != EOF)//读到的数据不等于文件尾{printf("%c",ch);}printf("\n");fclose(f_read);
}

读取成功:这里出现了一个EOF,全称为:END OF FILE文件尾的意思。

三、文件读写:按行和块读写

1.按行进行写fputs();

函数原型:int fputs(const char *str, FILE *stream);
函数功能:按行进行写
函数参数:
str:这是一个数组,包含了要写入的以空字符终止的字符序列
stream:指向FILE对象的指针
函数返回值:
成功:返回一个非负值
失败:返回EOF
void test()
{//写文件FILE* f_write = fopen("./2.txt","w+");//w+可读可写if (f_write == NULL){return;}char* buf[] = {"哈哈哈哈哈哈\n","嘿嘿嘿嘿嘿嘿\n","啦啦啦啦啦啦\n","吼吼吼吼吼吼\n"};for (int i=0; i<4; i++){fputs(buf[i],f_write);//写入}fclose(f_write);
}

写入成功:

2.按行进行读fgets();

函数原型:char *fgets(char *str, int n, FILE *stream);
函数功能:按行进行读
函数参数:
str:这是指向一个字符数组的指针,该数组存储了要读取的字符串。
n:这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
stream:这是指向FILE对象的指针,该FILE对象标识了要从中读取字符的流。
函数返回值:
成功:如果成功,该函数返回相同的 tr参数。如果到达文件末尾或者没有读取到任何字符,str的内容保持不变,并返回一个空指针。
失败:返回一个空指针。
void test()
{//读文件FILE* f_read = fopen("./2.txt","r");if (f_read == NULL){return;}while(!feof(f_read))//foef判断是否读到文件尾{char temp[1024] = {0};fgets(temp,1024,f_read);printf("%s",temp);}fclose(f_read);
}

读取成功:

3.按块进行写fwrite();

函数原型:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
函数功能:按块进行写
函数参数:
ptr:这是指向要被写入的元素数组的指针。
size:这是要被写入的每个元素的大小,以字节为单位。
nmemb:这是元素的个数,每个元素的大小为size字节。
stream:这是指向FILE对象的指针,该FILE对象指定了一个输出流。
函数返回值:
成功:该函数返回一个size_t对象,表示元素的总数,该对象是一个整型数据类型
失败:如果该数字与nmemb参数不同,则会显示一个错误
//按块进行读
struct Hero
{char name[16];int age;
};void test()
{//写文件FILE* f_write = fopen("./3.txt","wb");//二进制方式写入if (f_write == NULL){return;}struct Hero heros[] = {{"瑞文",66},{"瑞兹",77},{"德莱文",88},{"卡萨丁",99}};for(int i=0; i<4; i++){//参数1:数据地址 残数2:块的大小 参数3:块的个数  参数4:文件指针fwrite(&heros[i],sizeof(struct Hero),1,f_write);}fclose(f_write);
}

写入成功:此时文档是以二进制方式写入的,我们可能看不懂,目的是打开成功就好了,主要能够取出来。

4.按块进行读fread();

函数原型:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
函数功能:按块进行读
函数参数:
ptr:这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
size:这是要读取的每个元素的大小,以字节为单位。
nmemb:这是元素的个数,每个元素的大小为size字节。
stream:这是指向FILE对象的指针,该FILE对象指定了一个输入流。
函数返回值:
成功:读取的元素总数会以 ize_t对象返回,size_t对象是一个整型数据类型。
失败:如果总数与nmemb参数不同,则可能发生了一个错误或者到达了文件末尾。
struct Hero
{char name[16];int age;
};void test()
{//读文件FILE* f_read = fopen("./3.txt","rb");if (f_read == NULL){return;}struct Hero temp[4];//参数1:数据地址 残数2:块的大小 参数3:块的个数  参数4:文件指针fread(&temp,sizeof(struct Hero),4,f_read);for (int i=0; i<4; i++){printf("姓名:%s  年龄:%d\n",temp[i].name,temp[i].age);}fclose(f_read);
}

读取成功:

四、文件读写:格式化和随机位置

1.格式化方式进行写文件fscanf();

函数原型:int fscanf(FILE *stream, const char *format, ...);
函数功能:格式化方式进行写文件
函数参数:
stream:这是指向 FILE 对象的指针,该 FILE 对象标识了流。
format:这是C字符串,包含了以下各项中的一个或多个:空格字符、非空格字符和 format说明符。
函数返回值:
成功:成功,该函数返回成功匹配和赋值的个数。
失败:如果到达文件末尾或发生读错误,则返回EOF。
void test()
{//写文件FILE* f_write = fopen("./4.txt","w");if (f_write == NULL){return;}fprintf(f_write,"hello world %s","abcd");fclose(f_write);
}

写入成功:

2.格式化方式进行读文件fprintf();

函数原型:int fprintf(FILE *stream, const char *format, ...);
函数功能:格式化方式进行读文件
函数参数:
stream:这是指向 FILE 对象的指针,该 FILE 对象标识了流。
format:这是 C 字符串,包含了要被写入到流 stream 中的文本。
函数返回值:
成功:返回写入的字符总数。
失败:返回一个负数。
void test()
{//读文件FILE* f_read = fopen("./4.txt","r");if (f_read == NULL){return;}char temp[1024] = {0};while (!feof(f_read)){fscanf(f_read,"%s",temp);printf("%s\n",temp);//碰到空格会换一行}fclose(f_read);
}

读取成功:

3.移动光标fseek();

函数原型:int fseek(FILE *stream, long int offset, int whence);
函数功能:移动光标
函数参数:
stream:这是指向 FILE 对象的指针,该 FILE 对象标识了流。
offset:这是相对 whence 的偏移量,以字节为单位。
whence:这是表示开始添加偏移 offset 的位置。
它一般指定为下列常量之一:
SEEK_SET    文件的开头
SEEK_CUR    文件指针的当前位置
SEEK_END    文件的末尾
函数返回值:
成功:该函数返回零。
失败:返回非零值。
struct Hero
{char name[16];int age;
};void test()
{FILE* f_write = fopen("./5.txt","wb");//二进制方式写入if (f_write == NULL){return;}struct Hero heros[] = {{"瑞文",66},{"瑞兹",77},{"德莱文",88},{"卡萨丁",99}};for(int i=0; i<4; i++){fwrite(&heros[i],sizeof(struct Hero),1,f_write);}fclose(f_write);//读文件FILE* f_read = fopen("./5.txt","rb");if (f_read == NULL){return;}struct    Hero tempHero;//移动光标,例如我们想看将光标移动到第三行并输出//参数1:文件指针 参数2:偏移大小 参数3:起始位置//SEEK_SET从开始  SEEK_END从结尾  SEEK_CUR从当前位置fseek(f_read,sizeof(struct Hero)*2,SEEK_SET);//fseek(f_read,-(long)sizeof(struct Hero)*2,SEEK_END);也可以偏移成功fread(&tempHero,sizeof(struct Hero),1,f_read);printf("姓名:%s 年龄:%d\n",tempHero.name,tempHero.age);fclose(f_read);
}

4.用于得到文件位置指针当前位置相对于文件首的偏移字节数。ftell();

函数原型:long int ftell(FILE *stream);
函数功能:用于得到文件位置指针当前位置相对于文件首的偏移字节数
函数参数:
stream:这是指向 FILE 对象的指针,该FILE对象标识了流。
函数返回值:
成功:返回位置标识符的当前值
失败:发生错误,则返回 -1L,全局变量 errno 被设置为一个正值。

经常与fseek配合使用。
如下例子:

struct Hero
{char name[16];int age;
};void test()
{FILE* f_write = fopen("./5.txt","wb");//二进制方式写入if (f_write == NULL){return;}struct Hero heros[] = {{"瑞文",66},{"瑞兹",77},{"德莱文",88},{"卡萨丁",99}};for(int i=0; i<4; i++){fwrite(&heros[i],sizeof(struct Hero),1,f_write);}fclose(f_write);//读文件FILE* f_read = fopen("./5.txt","rb");if (f_read == NULL){return;}struct    Hero tempHero;//移动光标,例如我们想看将光标移动到第三行并输出//fseek(f_read,-(long)sizeof(struct Hero)*2,SEEK_END);//rewind(f_read);//将文件光标置首fseek(f_read,sizeof(struct Hero)*2,SEEK_SET);fread(&tempHero,sizeof(struct Hero),1,f_read);printf("姓名:%s 年龄:%d\n",tempHero.name,tempHero.age);printf("%d\n",ftell(f_read));fclose(f_read);
}

输出结果:因为fseek移动光标到德莱文那块了,一个结构体变量大小为20,刚好移动了60字节。

5.文件光标置首rewind(); 在刚才的代码里,我们使用rewind();可以将文件光标置首部。

函数原型:void rewind(FILE *stream);
函数功能:文件光标置首
函数参数:
stream:这是指向 FILE 对象的指针,该FILE对象标识了流
函数返回值:该函数不返回任何值.
rewind(f_read);//将文件光标置首

打印结果:输出首部的瑞文。

C语言详解文件操作(一):文件操作基础概念、按照字符、按照行块、按照格式化和随机位置读写文件相关推荐

  1. python read_excel 参数_详解pandas库pd.read_excel操作读取excel文件参数整理与实例

    详解pandas库pd.read_excel操作读取excel文件参数整理与实例 来源:中文源码网    浏览: 次    日期:2019年11月5日 详解pandas库pd.read_excel操作 ...

  2. python read_excel header_详解pandas库pd.read_excel操作读取excel文件参数整理与实例

    除了使用xlrd库或者xlwt库进行对excel表格的操作读与写,而且pandas库同样支持excel的操作:且pandas操作更加简介方便. 首先是pd.read_excel的参数:函数为: pd. ...

  3. Drools 规则语言详解(上)

    http://www.blogjava.net/guangnian0412/archive/2006/06/09/51574.html http://www.blogjava.net/guangnia ...

  4. php 赋值给 dom对象,详解PHP原生DOM对象操作XML的方法

    详解PHP原生DOM对象操作XML的方法 发布于 2017-08-08 20:15:29 | 80 次阅读 | 评论: 0 | 来源: 网友投递 PHP开源脚本语言PHP(外文名: Hypertext ...

  5. 克鲁斯卡尔算法c语言,Kruskal算法(一)之 C语言详解

    最小生成树 在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的最小生成树. 例如,对于如上图G4所示的连通网可以有多棵权值总和 ...

  6. 如何用c语言编写stm32的程序吗,STM32入门C语言详解

    <STM32入门C语言详解>由会员分享,可在线阅读,更多相关<STM32入门C语言详解(6页珍藏版)>请在人人文库网上搜索. 1.最新 料推荐阅读 flash : 芯片内部存储 ...

  7. HTML超文本标记语言详解

    HTML超文本标记语言详解 Hyper Text Markup Language(超文本标记语言) 现在的开发版本一般为HTML5+CSS3 W3C标准:World Wide Web Consorti ...

  8. c++指针详解_c语言详解sizeof

    一.sizeof的概念 sizeof是C语言的一种单目操作符,如C语言的其他操作符++.--等. 它并不是函数. sizeof操作符以字节形式给出了其操作数的存储大小. 操作数可以是一个表达式或括在括 ...

  9. 排座系统c语言,2008noip排座位C语言详解.doc

    2008noip排座位C语言详解 2008noip排座位C语言详解 2.排座椅 (seat.pas/c/cpp)D对同学上课时会交头接耳.同学们在教室中坐成了M行N列,坐在第i行第j列 的同学的位置是 ...

最新文章

  1. linux php-fpm启动失败,linux运行php-fpm遇到问题
  2. 奇淫异巧之 PHP 后门
  3. php去掉查询返回的字段序列号,php – 为返回的MySQL查询添加编号列表列
  4. 前端学习(2762):如何使用scss
  5. Java工作笔记-使用Maven创建Spring Boot并生成war包外部tocamt运行
  6. js实现文章显示部分内容
  7. C# 与C++的数据转换
  8. 广州软件性能测试培训,Loadrunner企业级性能测试课程 广州八神软件性能测试实战教程 炼数性能测试视频...
  9. Layer 2 DAO 基础协议 Metis 上线 Alpha 测试网
  10. 蓝桥杯 ADV-221 算法提高 7-1用宏求球的体积
  11. 心路历程5:雨天 --by Tsui
  12. 人工智能技术涉及到的学科有哪些,22年最新
  13. iOS 加粗字体方法 (不改变字体字号只加粗文字)
  14. Java接口,多态,向上转型,向下转型的意义
  15. java mail 20m附件_Gmail的最大附件调整到20M了
  16. 外贸企业邮箱域名是什么?企业内部邮箱域名注册解析怎么做?
  17. 【工具】MobaXterm常用设置
  18. 389-MySQL数据库代码封装
  19. 具有手摇柴油机带动的油泵和空压机带动的柴油喷嘴的涡轮喷气式飞机
  20. ArcGIS遥感影像图像融合后利用掩膜去黑边

热门文章

  1. gdufe acm 1363 校庆嘉宾
  2. printf函数 重定义printf函数。
  3. 人工智能之二分类的简单实现
  4. 数据分析见解-数据异常波动
  5. 踩坑之 —— ireport导出空白(java)
  6. 简单使用MenuItem特性
  7. 代码整洁之道—变量名
  8. BZOJ2140稳定婚姻
  9. 解决netgear路由器总掉线的问题
  10. 误格式化硬盘怎么办?分享硬盘格式化恢复的实用方法