文件讲解—【C语言】

news/2025/5/18 17:05:21

 目录

1.为什么使用文件

2. 什么是文件

2.1 程序文件

2.2 数据文件

2.3 文件名

3. 文件的打开和关闭 

3.1 文件指针

3.2 文件的打开和关闭

4. 文件的顺序读写

4.1 顺序读写函数介绍

 4.2 对比一组函数

例子

例子

5.3 rewind

例子 

6. 文本文件和二进制文件

测试代码

7. 文件读取结束的判定

7.1 被错误使用的feof

文本文件的例子

二进制文件的例子

 8. 文件缓冲区


学习本篇博客可以更好的理解通讯录的文件版,搞定期末C语言程序设计

1.为什么使用文件

        我们前面学习结构体时,写通讯录的程序,当通讯录运行起来的时候,可以给通讯录中增加、删除数 据,此时数据是存放在内存中,当程序退出的时候,通讯录中的数据自然就不存在了,等下次运行通讯 录程序的时候,数据又得重新录入,如果使用这样的通讯录就很难受。

        我们在想既然是通讯录就应该把信息记录下来,只有我们自己选择删除数据的时候,数据才不复存在。 这就涉及到了数据持久化的问题,我们一般数据持久化的方法有,把数据存放在磁盘文件、存放到数据 库等方式。 使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。


2. 什么是文件

磁盘上的文件是文件。

但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

2.1 程序文件

包括源程序文件(后缀为.c)—— 程序员自己创建的文件C语言后缀为.c  、(C++为.cpp)

目标文件(windows环境后缀为.obj)—— 代码编译过程中的中间文件

可执行程序(windows环境后缀为.exe)—— 可执行文件(运行框)

2.2 数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件, 或者输出内容的文件。

本章讨论的是数据文件。 在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。

其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理 的就是磁盘上文件。

2.3 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。

文件名包含3部分:文件路径+文件名主干+文件后缀

例如: c:\code\test.txt  ——(c:\code\)是文件路径、test是文件名主干、.txt(是后缀名)

为了方便起见,文件标识常被称为文件名。


3. 文件的打开和关闭 

3.1 文件指针

缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统 声明的,取名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*的指针变量:

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

比如

3.2 文件的打开和关闭

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件

在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指 针和文件的关系。

ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。

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

打开方式如下表


4. 文件的顺序读写

4.1 顺序读写函数介绍

 4.2 对比一组函数

scanf/fscanf/sscanf

printf/fprintf/sprintf


5. 文件的随机读写

5.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;
}

5.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-portablesize=ftell (pFile);fclose (pFile);printf ("Size of myfile.txt: %ld bytes.\n",size);}return 0;
}

5.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';puts (buffer);puts (buffer);return 0;
}

6. 文本文件和二进制文件

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。


如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。

一个数据在内存中是怎么存储的呢?

字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。 如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2013测试)。

测试代码

#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;
}

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,要求处理EOFFILE* fp = fopen("test.txt", "r");if(!fp) {perror("File opening failed");return EXIT_FAILURE;}//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOFwhile ((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 handlingif (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>
//VS2013 WIN10环境测试
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语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文 件。 如果不做,可能导致读写文件的问题。



因为参加活动,又临近期末,导致本篇博客写的比较赶,比较粗糙,在日后等小余有时间的话,会把本篇博客重新优化下。

如果觉得文章不错,期待你的一键三连哦,你个鼓励是我创作的动力之源,让我们一起加油,顶峰相见!!!

 

 

文章来源:https://blog.csdn.net/qq_58286439/article/details/131144363
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:https://dhexx.cn/news/show-4653053.html

相关文章

万字详解普遍操作系统进程七态与Linux进程七态

作为一个称职的系统管理员&#xff0c;为了更熟悉进程的管理流程&#xff0c;我们必须要知道进程的不同状态所对应的意义。 目录 了解进程状态普遍操作系统的概念就绪状态运行状态等待状态阻塞状态挂起状态暂停状态终止状态 Linux下的进程状态R (running)运行状态S (sleeping)可…

内存储器题目

1.和外存储器相比&#xff0c;内存储器的特点是 容量小&#xff0c;速度快&#xff0c;成本高 内存储器是指计算机的主存储器和位于CPU与主存储器之间的高速缓冲存储器cache.外存储器是指计算机的辅助存储器,包括硬盘、软盘、光盘等。 2. 640KB的内存容量为&#xff1a; 655360…

Vue模板语法的缩写是什么?

Vue模板语法缩写是VTL&#xff08;View Template Language&#xff09;&#xff0c;这是一种用于构建用户界面的声明式编程语言。它基于HTML&#xff0c;但具有更强大的数据绑定功能。下面是一些VTL的例子&#xff1a; 绑定文本&#xff1a; <p>{{ message }}</p>…

Spring高手之路4——深度解析Spring内置作用域及其在实践中的应用

文章目录 1. Spring的内置作用域2. singleton作用域2.1 singleton作用域的定义和用途2.2 singleton作用域线程安全问题 3. prototype作用域3.1 prototype作用域的定义和用途3.2 prototype作用域在开发中的例子 4. request作用域&#xff08;了解&#xff09;5. session作用域&a…

【Python开发】FastAPI 09:middleware 中间件及跨域

FastAPI 提供了一些中间件来增强它的功能&#xff0c;类似于 Spring 的切面编程&#xff0c;中间件可以在请求处理前或处理后执行一些操作&#xff0c;例如记录日志、添加请求头、鉴权等&#xff0c;跨域也是 FastAPI 中间件的一部分。 目录 1 中间件 1.1 创建中间件 1.2 使…

虚函数表不一定总是在对象的起始位置

在我之前的一篇文章 “COM 对象的内存布局”中&#xff0c;作为举例&#xff0c;我将对象的虚函数表指针放置在了底层 C 对象的起始位置&#xff0c;但是值得注意的是&#xff0c;虚函数表指针指向的位置并没有一个实际的标准。即使将虚函数表放置在对象中间&#xff0c;甚至是…

使用 Python Selenium 提取动态生成下拉选项

在进行网络数据采集和数据分析时&#xff0c;处理动态生成的下拉菜单是一个常见的挑战。Selenium是一个强大的Python库&#xff0c;可以让你自动化浏览器操作&#xff0c;比如从动态生成的下拉菜单中选择选项。这是一个常见的网页爬虫和数据收集者面临的挑战&#xff0c;但是Se…

普中自动下载软件1.86下载程序失败案例

今天在用开发板做一个功能&#xff0c;下载的时候报错了&#xff0c;说芯片超时 确定驱动安装好了的 波特率也试了一圈 线也换过了 最后发现是芯片类型选错了&#xff0c;这个开发板是用的stc89c52,所以我选了图里这个&#xff0c;但是翻了开发板配套的资料&#xff0c;发现…

LinuxC编程——高级文件操作

目录 一、查询文件信息1、stat2、stat fstat lstat区别 二、目录操作2.1 opendir2.2 readdir2.3 closedir例练习&#xff1a;实现ls操作 三、库3.1 库的定义3.2 库的分类3.2.1 静态库3.2.2 动态库 3.3 创建库3.3.1 静态库制作3.3.2 动态库制作 一、查询文件信息 1、stat int …

英语学习:M开头

machine 机器 mad 发疯的&#xff0c;生气的 madam 女士&#xff0c;夫人 madame 夫人 magazine 杂志 magic 有魔力的 maid 女仆&#xff0c;侍女 mail 邮递 mailbox 邮箱 mainland 大陆 major 较大的&#xff0c;主要的 majority 大多数 male 雄的 man 人类 man…