C语言⽂件操作

news2024/10/5 20:27:02

1. 为什么使⽤⽂件

如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存,我们可以使⽤⽂件。

2. 什么是⽂件

磁盘上的⽂件是⽂件。
但是在程序设计中,我们⼀般谈的⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类
的)。

2.1 程序⽂件

程序⽂件包括源程序⽂件(后缀为.c),⽬标⽂件(windows环境后缀为.obj),可执⾏程序(windows环境后缀为.exe)。

2.2 数据⽂件

⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,⽐如程序运⾏需要从中读取数据的⽂件,或者输出内容的⽂件。
本章讨论的是数据⽂件。
在以前各章所处理数据的输⼊输出都是以终端为对象的,即从终端的键盘输⼊数据,运⾏结果显⽰到显⽰器上。其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这处理的就是磁盘上⽂件。

2.3 ⽂件名

⼀个⽂件要有⼀个唯⼀的⽂件标识,以便⽤⼾识别和引⽤。
⽂件名包含3部分:⽂件路径+⽂件名主⼲+⽂件后缀。
例如: c:\code\test.txt
为了⽅便起⻅,⽂件标识常被称为⽂件名

3. ⼆进制⽂件和⽂本⽂件

根据数据的组织形式,数据⽂件被称为⽂本⽂件或者⼆进制⽂件。
数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存,就是⼆进制⽂件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是⽂本⽂件。
⼀个数据在内存中是怎么存储的呢?
字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽⼆进制形式输出,则在磁盘上只占4个字节(VS2019测试)

测试代码:

#include <stdio.h>
int main()
{
int a = 10000;
 FILE* pf = fopen("test.txt", "wb");
fwrite(&a, 4, 1, pf); //⼆进制的形式写到⽂件中
fclose(pf);
pf = NULL;
return 0;
}

在VS上打开⼆进制⽂件:

 

                                             10000在⼆进制⽂件中

4. ⽂件的打开和关闭 

4.1 流和标准流

4.1.1 流

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出操作各不相同,为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了流的概念,我们可以把流想象成流淌着字符的河。
C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流操作的。
⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开流,然后操作。

4.1.2 标准流 

那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?
那是因为C语⾔程序在启动的时候,默认打开了3个流:
• stdin   标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。
• stdout  标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出
流中。
• stderr   标准错误流,⼤多数环境中输出到显⽰器界⾯。
这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。
stdin、stdout、stderr?三个流的类型是: FILE* ,通常称为⽂件指针。
C语⾔中,就是通过 FILE* 的⽂件指针来维护流的各种操作的。

4.2 ⽂件指针

缓冲⽂件系统中,关键的概念是“⽂件类型指针”,简称“⽂件指针”。
每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系统声明的,取名FILE.
例如,VS2013编译环境提供的 stdio.h 头⽂件中有以下的⽂件类型申明:

struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;

不同的C编译器的FILE类型包含的内容不完全相同,但是⼤同⼩异。
每当打开⼀个⽂件的时候,系统会根据⽂件的情况⾃动创建⼀个FILE结构的变量,并填充其中的信
息,使⽤者不必关⼼细节。
⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使⽤起来更加⽅便。
下⾯我们可以创建⼀个FILE*的指针变量: 

FILE* pf; //⽂件指针变量

定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变量)。通过该⽂件信息区中的信息就能够访问该⽂件。也就是说,通过⽂件指针变量能够间接找到与它关联的⽂件 。

⽐如:

4.3 ⽂件的打开和关闭 

⽂件在读写之前应该先打开⽂件,在使⽤结束之后应该关闭⽂件。
在编写程序的时候,在打开⽂件的同时,都会返回⼀个FILE*的指针变量指向该⽂件,也相当于建⽴了指针和⽂件的关系。
ANSIC 规定使⽤ fopen 函数来打开⽂件, fclose 来关闭⽂件。

//打开⽂件
FILE * fopen ( const char * filename, const char * mode );
//关闭⽂件
int fclose ( FILE * stream );

mode表⽰⽂件的打开模式,下⾯都是⽂件的打开模式:

⽂件使⽤⽅式  含义  如果指定⽂件不存在 
“r”(只读)  为了输⼊数据,打开⼀个已经存在的⽂本⽂件  出错 
“w”(只写)  为了输出数据,打开⼀个⽂本⽂件 建⽴⼀个新的⽂件 
“a”(追加)  向⽂本⽂件尾添加数据? 建⽴⼀个新的⽂件
“rb”(只读)  为了输⼊数据,打开⼀个⼆进制⽂件  出错
“wb”(只写)  为了输出数据,打开⼀个⼆进制⽂件  建⽴⼀个新的⽂件
“ab”(追加)  向⼀个⼆进制⽂件尾添加数据   建⽴⼀个新的⽂件
“r+”(读写) 为了读和写,打开⼀个⽂本⽂件  出错
“w+”(读写)  为了读和写,建议⼀个新的⽂件  建⽴⼀个新的⽂件
“a+”(读写)  打开⼀个⽂件,在⽂件尾进⾏读写  建⽴⼀个新的⽂件
“rb+”(读写)  为了读和写打开⼀个⼆进制⽂件  出错 
“wb+”(读
写)
为了读和写,新建⼀个新的⼆进制⽂件 建⽴⼀个新的⽂件
“ab+”(
写)
打开⼀个⼆进制⽂件,在⽂件尾进⾏读和写 建⽴⼀个新的⽂件

实例代码:

/* fopen fclose example */
#include <stdio.h>
int main ()
{
FILE * pFile;
//打开⽂件
pFile = fopen ("myfile.txt","w");
//⽂件操作
if (pFile!=NULL)
{
fputs ("fopen example",pFile);
//关闭⽂件
fclose (pFile);
}
return 0;
}

我们实操看看效果

我们可以观察到创建了一个date.txt的 文件。

5. ⽂件的顺序读写 

5.1 顺序读写函数介绍

上⾯说的适⽤于所有输⼊流⼀般指适⽤于标准输⼊流和其他输⼊流(如⽂件输⼊流);所有输出流⼀般指适⽤于标准输出流和其他输出流(如⽂件输出流)。 

5.2 对⽐⼀组函数:

scanf/fscanf/sscanf
printf/fprintf/sprintf

6. ⽂件的随机读写

6.1 fseek

根据⽂件指针的位置和偏移量来定位⽂件指针.

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

例⼦:

/* fseek example */
#include <stdio.h>
int main ()
{
FILE * pFile;
pFile = fopen ( "example.txt" , "wb" );
fputs ( "This is an apple." , pFile );
fseek ( pFile , 9 , SEEK_SET );
fputs ( " sam" , pFile );
fclose ( pFile );
return 0;
}

6.2 ftell

返回⽂件指针相对于起始位置的偏移量

long int ftell ( FILE * stream );

例⼦:

/* ftell example : getting size of a file */
#include <stdio.h>
int main ()
{
FILE * pFile;
long size;
pFile = fopen ("myfile.txt","rb");
if (pFile==NULL)
perror ("Error opening file");
else
{
fseek (pFile, 0, SEEK_END); // non-portable
size=ftell (pFile);
fclose (pFile);
printf ("Size of myfile.txt: %ld bytes.\n",size);
}
return 0;
}

6.3 rewind 

让⽂件指针的位置回到⽂件的起始位置

void rewind ( FILE * stream );

例⼦:

/* rewind example */
#include <stdio.h>
int main ()
{
int n;
FILE * pFile;
char buffer [27];
pFile = fopen ("myfile.txt","w+");
for ( n='A' ; n<='Z' ; n++)
fputc ( n, pFile);
rewind (pFile);
fread (buffer,1,26,pFile);
fclose (pFile);
buffer[26]='\0';
printf(buffer);
return 0;
} 

7. ⽂件读取结束的判定 

7.1 被错误使⽤的 feof

牢记:在⽂件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的是否结束。
feof 的作⽤是:当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束。
1. ⽂本⽂件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
例如:
• fgetc 判断是否为 EOF .
• fgets 判断返回值是否为 NULL .
2. ⼆进制⽂件的读取结束判断,判断返回值是否⼩于实际要读的个数。
例如:
• fread判断返回值是否⼩于实际要读的个数。

⽂本⽂件的例⼦:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int c; // 注意:int,⾮char,要求处理EOF
FILE* fp = fopen("test.txt", "r");
if(!fp) {
perror("File opening failed");
return EXIT_FAILURE;
}
//fgetc 当读取失败的时候或者遇到⽂件结束的时候,都会返回EOF
while ((c = fgetc(fp)) != EOF) // 标准C I/O读取⽂件循环
{
putchar(c);
}
//判断是什么原因结束的
if (ferror(fp))
puts("I/O error when reading");
else if (feof(fp))
puts("End of file reached successfully");
fclose(fp);
}

⼆进制⽂件的例⼦:

#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
double a[SIZE] = {1.,2.,3.,4.,5.};
FILE *fp = fopen("test.bin", "wb"); // 必须⽤⼆进制模式
fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
fclose(fp);
 double b[SIZE];
fp = fopen("test.bin","rb");
size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
if(ret_code == SIZE) {
puts("Array read successfully, contents: ");
for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
putchar('\n');
} else { // error handling
if (feof(fp))
printf("Error reading test.bin: unexpected end of file\n");
else if (ferror(fp)) {
perror("Error reading test.bin");
}
}
fclose(fp);
}

8. ⽂件缓冲区 

ANSIC?标准采⽤“缓冲⽂件系统”处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为程序中每⼀个正在使⽤的⽂件开辟⼀块“⽂件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才⼀起送到磁盘上。如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输⼊到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的⼤⼩根据C编译系统决定的。

#include <stdio.h>
#include <windows.h>
//VS2019 WIN11环境测试
int main()
{
FILE*pf = fopen("test.txt", "w");
fputs("abcdef", pf); //先将代码放在输出缓冲区
printf("睡眠10秒-已经写数据了,打开test.txt⽂件,发现⽂件没有内容\n");
Sleep(10000);
printf("刷新缓冲区\n");
fflush(pf); //刷新缓冲区时,才将输出缓冲区的数据写到⽂件(磁盘)
//注:fflush 在⾼版本的VS上不能使⽤了
printf("再睡眠10秒-此时,再次打开test.txt⽂件,⽂件有内容了\n");
Sleep(10000);
fclose(pf);
//注:fclose在关闭⽂件的时候,也会刷新缓冲区
pf = NULL;
return 0;
}

这⾥可以得出⼀个结论:
因为有缓冲区的存在,C语⾔在操作⽂件的时候,需要做刷新缓冲区或者在⽂件操作结束的时候关闭⽂件。
如果不做,可能导致读写⽂件的问题。 

本期内容就到这里了

下期内容是  C语言的编译和链接

请大家持续关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1510325.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

羊大师分析,羊奶养生智慧

羊大师分析&#xff0c;羊奶养生智慧 羊奶&#xff0c;这一古老而自然的饮品&#xff0c;近年来逐渐受到越来越多人的青睐。其独特的营养价值与养生功效&#xff0c;使得羊奶成为了追求健康生活的人们的理想选择。那么&#xff0c;羊奶究竟蕴藏着怎样的养生智慧呢&#xff1f;…

MQ的相关概念

微服务间通讯有同步和异步两种方式&#xff1a; 同步通讯&#xff1a;就像打电话&#xff0c;需要实时响应。异步通讯&#xff1a;就像发邮件&#xff0c;不需要马上回复。 同步通讯 同步调用的优点&#xff1a; 时效性较强&#xff0c;可以立即得到结果 Feign调用就属于同…

计算机网络:应用层知识点汇总

文章目录 一、网络应用模型二、域名系统&#xff08;DNS&#xff09;三、文本传输协议&#xff08;FTP&#xff09;四、电子邮件五、万维网和HTTP协议 一、网络应用模型 p2p也就是对等模型 二、域名系统&#xff08;DNS&#xff09; 我们知道&#xff0c;随着人们建立一个网站…

Redis底层数据结构之String

文章目录 1. 前提回顾2. RedisObject三大数据类型简介3. SDS字符串4. SDS字符串源码分析5. 总结 1. 前提回顾 前面我们说到redis的String数据结构在底层有多种编码方式。例如我们执行下面两条语句 set k1 v1 set age 17我们查看类型&#xff0c;发现这类型都是String类型 我们…

动态规划课堂5-----子序列问题(动态规划 + 哈希表)

目录 引言&#xff1a; 例题1&#xff1a;最长递增子序列 例题2&#xff1a;最长定差子序列 例题3&#xff1a;最长的斐波那契子序列的长度 例题4&#xff1a;最长等差数列 例题5&#xff1a;等差数列划分II-子序列 结语&#xff1a; 引言&#xff1a; 要想解决子序列问…

pc端vue2项目使用uniapp组件

项目示例下载 运行实例&#xff1a; 这是我在pc端做移动端底代码时的需求&#xff0c;只能在vue2使用&#xff0c;vue3暂时不知道怎么兼容。 安装依赖包时可能会报&#xff1a;npm install Failed to set up Chromium r756035! Set “PUPPETEER_SKIP_DOWNLOAD” env variable …

伪分布式Spark集群搭建

一、软件环境 软 件 版 本 安 装 包 VMware虚拟机 16 VMware-workstation-full-16.2.2-19200509.exe SSH连接工具 FinalShell Linux OS CentOS7.5 CentOS-7.5-x86_64-DVD-1804.iso JDK 1.8 jdk-8u161-linux-x64.tar.gz Spark 3.2.1 spark-3.2.1-bin-…

JVM的整体架构

JVM的整体架构 JVM的架构模型 基本上是基于栈的指令集架构 基于栈式架构的特点 设计和实现更简单&#xff0c;适用于资源受限的系统避开了寄存器的分配难题&#xff1a;使用零地址指令方式分配指令流中的指令大部分是零地址指令&#xff0c;其执行过程依赖于操作栈。指令集更…

AI写作一键生成原创文案,效率高!

AI写作一键生成原创文案&#xff0c;效率高&#xff01;当下时代&#xff0c;文案写作对于各个企业推广产品和服务显得隔外重要。优秀的文案能够吸引用户的注意力&#xff0c;激发购买欲望&#xff0c;从而为企业带来更多的销售机会。然而&#xff0c;对于许多人来说&#xff0…

【Python】新手入门学习:什么是工作目录?

【Python】新手入门学习&#xff1a;什么是工作目录&#xff1f; &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448; 希望得…

【Python机器学习系列】自助法计算机器学习评价指标的置信区间(案例+源码)

这是我的第235篇原创文章。 一、引言 Bootstrap方法是非常有用的一种统计学上的估计方法&#xff0c;是一类非参数Monte Carlo方法&#xff0c;其实质是对观测信息进行再抽样&#xff0c;进而对总体的分布特性进行统计推断。 自助法计算分类模型的AUC、准确率、特异度和灵敏…

商业楼宇一卡通解决方案(1)

智能楼宇发展 智能楼宇也称智能建筑,又称智能大厦。智能楼宇是将建筑技术、通信技术、计算机技术和控制技术等各方面的先进科学技术相互融合、合理集成为最优化的整体,具有工程投资合理、设备高度自动化、信息管理科学、服务高效优质、使用灵活方便和环境安全舒适等特点,是…

Caffeine--实现进程缓存

本地进程缓存特点 缓存在日常开发中起着至关重要的作用, 由于存储在内存中, 数据的读取速度非常快,能大量减少对数据库的访问,减少数据库的压力. 缓存分为两类: 分布式缓存, 例如Redis: 优点: 存储容量大, 可靠性更好, 可以在集群间共享缺点: 访问缓存存在网络开销场景: 缓存数…

Python网站的搭建和html基础

1.Python网站代码及讲解 一般我们搭建小型的网站就用flask库就行了。 &#xff08;1&#xff09;安装flask库 安装完python后&#xff0c;按住windows徽标键和r,弹出“运行”&#xff0c;在里面输入cmd。 回车打开&#xff0c;输入“pip install flask”。 &#xff08;2&am…

4. C++ 类的大小

C 类的大小 ​ C类的大小&#xff0c;是一个比较经典的问题&#xff0c;学过C后&#xff0c;应该对类大小有清晰的认识&#xff0c;长话短说&#xff0c;本文精简凝练&#xff0c;我们进入正题&#xff01;&#xff01;&#xff01; 1.类的大小与什么有关系&#xff1f; 与类…

C#,数值计算,解微分方程的龙格-库塔四阶方法与源代码

Carl Runge Martin Wilhelm Kutta 1 龙格-库塔四阶方法 数值分析中,龙格-库塔法(Runge-Kutta)是用于模拟常微分方程的解的重要的一类隐式或显式迭代法。这些技术由数学家卡尔龙格和马丁威尔海姆库塔于1900年左右发明。 对于一阶精度的欧拉公式有: yi+1=yi+h*K1  K1=f(…

Portraiture2024中文版广泛应用于人像处理的磨皮美化插件

Portraiture插件是一款广泛应用于人像处理的磨皮美化插件&#xff0c;尤其在Photoshop和Lightroom等图像编辑软件中备受欢迎。这款插件能够帮助用户快速实现智能磨皮效果&#xff0c;使皮肤看起来更加平滑细腻&#xff0c;同时保留自然纹理和其他重要细节。 Portraiture for Ph…

基于JAVA实现五子棋游戏设计【附项目源码】分享

基于JAVA实现五子棋游戏设计&#xff1a; 项目源码地址&#xff1a;https://download.csdn.net/download/weixin_43894652/88842612 一、引言 五子棋&#xff0c;又称连珠、连五、五目、五目棋等&#xff0c;是一种传统的棋类游戏。本需求文档旨在详细阐述一个基于Java环境开…

LIGHTHOUSE Apex RBP应用案例|汽车涂装行业 电动汽车电池制造行业的颗粒物监测首选

Lighthouse ApexBP汽车制造中的颗粒物监测技术无疑是汽车制造领域的一项革命性发展。它不仅提供了全面、高精度的颗粒检测&#xff0c;而且能够轻松集成到现有的制造流程中&#xff0c;满足自动化需求&#xff0c;加强质量控制&#xff0c;确保电动汽车电池生产的安全性和效率。…

展览厅设计如何创新而独特

一、独特的建筑外观 展览厅的建筑外观是展览的第一印象&#xff0c;因此需要设计一个独特而有吸引力的外观。可以使用独特的建筑形态、创新的材料和结构&#xff0c;以及艺术化的立面设计。 二、灵活的展示空间 创新的展览厅设计应具备灵活的展示空间&#xff0c;以适应不同类型…