为什么使⽤⽂件?
如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存,我们可以使⽤⽂件。什么是⽂件?
磁盘上的⽂件是⽂件。但是在程序设计中,我们⼀般谈的⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类的)
程序⽂件:
程序⽂件包括源程序⽂件(后缀为.c),⽬标⽂件(windows环境后缀为.obj),可执⾏程序(windows环境后缀为.exe)。 其实我们可以理解程序文件就是我们写代码的文件(其可以运行)。源程序文件是还没经历编译和链接时的最初始的文件,而目标文件和可执行程序是源程序文件在编译,链接时产生的文件。
数据⽂件
⽂件的内容不是程序,不可以运行,该文件只能被读写数据。⽐如程序运⾏需要从中读取数据的⽂ 件,或者输出内容的⽂件,(其并不会被运行,只是拿来读写)在以前各章所处理据的输⼊输出都是以终端为对象的,即从终端的键盘输⼊数据,运⾏结果显⽰到显⽰器上。 其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使⽤,这⾥处理的就是磁盘上⽂件。
而我们今天本篇文件操作文章讨论的对象就是数据⽂件,并不是程序文件.接下来讲的都是跟数据文件有关的知识点。
文件名
⼀个⽂件要有⼀个唯⼀的⽂件标识,以便⽤⼾识别和引⽤。 ⽂件名包含3部分:⽂件路径+⽂件名主⼲+⽂件后缀 。 例如: c:\code\mycode\test.txt这里的c:\code\mycode\就是文件路径,test就是文件名主干,.txt就是文件后缀。
文件中不能包含这些字符: * ? " < > |
文件的后缀名决定了一个文件的默认打开方式
文件路径指的是从盘符到该文件所经历的路径中各符号名的集合 为了⽅便起⻅,⽂件标识常被称为⽂件名。文件名都是唯一的,绝不可能会有相同的。
二进制文件和文本文件
根据数据的组织形式,数据⽂件被称为⽂本⽂件或者⼆进制⽂件。
二进制文件
数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存,就是⼆进制⽂件。二进制文件里储存的都是数据在内存中存储的原形式。如下是二进制文件的储存情况,存的是10000在内存中的存储原形式.其在内存中的存储原形式为10 27 00 00 ,所以直接将其不加转换的存入到二进制文件中,(都还是十六进制形式)
对于最开始的00000000,我们也不清楚,可能是编码什么的,跟我们存入的数据没关系,没必要去理解。
要打开二进制文件并使其正常显示出其数据,我们就必须用二进制编译器,其它编译器都会显示出乱码(我们看不懂)
文本文件
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是⽂本⽂件。 这里说定义大家也搞不懂,那这里就带大家看下二进制文件和文本文件的区别应该就能懂了。 数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。 如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽⼆进制形式输出,则在磁盘上只占4个字节(VS2019测试)。
如上图,文本文件就是将其数据转换为ascall码形式的数据再储存在文本文件中。这样每个字符都要转换为ascall码值,所以就由四个字节变为5个字节去存储在文本文件中。
当我们打开文本文件时,显示出的依然是我们原来的值。举个例子,比如我们将400000存入文本文件时,我们打开文本文件后显示出来的是400000(原数据),并不是地址形式的数据。(大部分编译器都能打开并正常显示出数据)
文件的打开和关闭
流和标准流
流
我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出操作各不相同,我们程序员就是个写代码,不可能了解所有的不同设备之间的传递,这可太麻烦了,所以为了⽅便程序员对各种设备进⾏⽅便的操作,我们创造出了流这个东西。 c语言底层规定了流到不同设备之间的互相传输,不需要我们去进行操作,底层会自动帮我们去操作,所以我们只需要将数据传到流或者从流中提到数据就能实现整个过程。它跟个中转站一样。 C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流当中转站操作的。
所以我们想要读取数据或者输入数据从某外部设备中,都是必须要打开对应的流才能操作。
(该图片转载)
流是有明确的方向性的,所以分为两种,要么是输入流(从外部设备到内存),要么是输出流 (从内存向外部设备)。
标准流
那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流,却依然能执行(如scanf,printf没有打开流却依然能执行这些操作)
那是因为C语⾔程序在启动的时候,默认打开了3个流: • stdin(指向标准输入流) - 标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据。 • stdout (指向标准输出流)- 标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出 流中。 • stderr (指向标准错误流)- 标准错误流,⼤多数环境中输出到显⽰器界⾯。perror函数就是将错误信息输出到标准错误流中。(其流是输出错误信息到显示器上) 所以stdin,stdout,stderr类型都是FILE*。通常称为文件指针。
文件指针
缓冲⽂件系统中,关键的概念是“⽂件类型指针”,简称“⽂件指针”。 每个在系统中被打开的⽂件都会在内存中开辟了⼀个相应的⽂件信息区(文件必须要被打开才能有文件信息区),⽤来存放⽂件的相关信息(如⽂件的名字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系统声明的,取名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;
所以FILE类型为结构体(用了typedef将其重命名,其为结构体类型)
不同的C编译器的FILE类型包含的内容不完全相同,但是⼤同⼩异。 每当打开⼀个⽂件的时候,系统会根据⽂件的情况⾃动创建⼀个FILE结构体并填充其中的信 息,使⽤者不必关⼼细节。 文件信息区其实就是流,所以并不是只有文件才有对应的文件信息区。屏幕,键盘等都有对应的文件信息区(也就是流)。 流的类型就都为FILE类型。 对于stderr,stdin,stdout它们其实就是文件信息区,在程序开始后就自动在内存里开辟FILE类型的空间,它们对应着键盘,显示器,作为中转站去使用。 ⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使⽤起来更加⽅便。 下⾯我们可以创建⼀个FILE*的指针变量: FILE* pf;//⽂件指针变量
定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变量)。通过该⽂件信息区中的信息就能够访问该⽂件。(这证明了其文件信息区为中转站,而流也为中转站,更能证明流就是文件信息区。)也就是说,通过⽂件指针变量能够间接找到与 它关联的⽂件。 文件的打开和关闭
⽂件在读写之前应该先打开⽂件,在使⽤结束之后应该关闭⽂件。 在编写程序的时候,在打开⽂件的同时,都会返回⼀个FILE*的指针变量指向该⽂件,也相当于建⽴了指针和⽂件的关系。 ANSIC 规定使⽤ fopen 函数来打开⽂件, fclose 来关闭⽂件。
//打开⽂件FILE * fopen ( const char * filename, const char * mode );//关闭⽂件int fclose ( FILE * stream );
fopen函数
FILE * fopen ( const char * filename, const char * mode );
第一个参数是文件名,第二个参数是打开方式。最终该函数会返回其文件的文件信息区的地址。
fopen第一个参数
对于该文件名,有相对路径和绝对路径。
相对路径:如第一个参数直接写"data,txt",代表着该文件与你的这个项目文件在同一个文件夹里(同一个目录里)。
当然还可以用.和..去修饰相对路径。 如”./../../data.txt“表示data.txt在该项目文件的上上个目录中。
绝对路径:
就是文件名中直接写根本的路径,根本路径我们需要在属性中看.
如图上中的文件在桌面上,其属性中的位置就是其桌面的位置,将其我们的目标文件名改为“c:\users\zhu xuan\Desktop\data.txt”就代表这是在桌面上的data.txt文件,并且由于\为转义字符,所以在代码中需要改为\\才能不影响结果。如“c:\\users\\zhu xuan\\Desktop\\data.txt”。
fopen第二个参数
有以下的打开方式:
现在浅谈一下“r”“w”“a”。
“r”:如果不存在该文本文件,则返回一个NULL指针,且系统会出错(但程序不会崩溃,依旧运行,我们可以用perror去打印出其错误)。
如果存在该文本文件,则打开该文本文件,且只能对该文件的数据进行读取使用(不能输入数据对该文件进行修改)。
”w“:如果不存在该文本文件,则建立一个新的文本文件。
如果存在该文本文件,则打开该文件且格式化该文件(将该文件内容清除),且只能对该文件的数据进行输入数据(不能读取该文件)。
”a“:如果不存在该文本文件,则建立一个新的文本文件。
如果存在该文本文件,则打开该文件(不会格式化该文件),保留原来的内容并继续追加数据输入到文件中(不能读取该文件)
其总共有12种打开方式,这里我们只讲三种(对于有r字符的打卡方式,都是不存在该文件则返回NULL,其他打开方式都是再建立一个文件)。
对于其fopen打开方式的更多细节内容,我推荐一篇文章,这里讲的更仔细。
【C 语言】文件操作 ( fopen 文件打开方式详解 )-CSDN博客
这篇文章讲了其中七种的打开方式,讲的很详细了,看懂了这七种其他的自然手到擒来。还讲了个rw+打开方式,rw+用到的很少无需关注。
fclose函数
这个就很简单了,只需要将该文件的文件信息区的地址填入到fclose括号里面,就能销毁掉该文件的文件信息区(也就是关闭文件)
总结
所以这就是我们的c语言文件读写的第一部分(这是我在一月份c语言时期写的存稿,所以书写可能没有现在美观,还请见谅)。 还希望各位大佬们能给个三连,点点关注,点点赞,发发评论呀,感谢各位大佬~❤️❤️??????