一文吃透文件操作
1. 为什么使用文件如果没有文件我们写的程序的数据是存储在电脑的内存中如果程序退出内存回收数据就丢失 了等再次运行程序是看不到上次程序的数据的如果要将数据进行持久化的保存我们可以使用文件。2. 什么是文件磁盘硬盘上的文件就是文件。但是我们在程序设计中一般分为两种文件程序文件和数据文件。2.1 程序文件程序文件包括源程序文件后缀为.c目标文件Windows环境为.obj可执行程序Windows环境为.eve。2.2 数据文件文件的内容不⼀定是程序而是程序运行时读写的数据比如程序运行需要从中读取数据的文件或者输出内容的文件。在以前各章所处理数据的输入输出都是以终端为对象的即从终端的键盘输入数据运行结果显示到显示器上。其实有时候我们会把信息输出到磁盘上当需要的时候再从磁盘上把数据读取到内存中使用这里处理的就是磁盘上文件。2.3 文件名一个文件要有一个唯一的标识那就是文件名文件名包括由3个部分组成文件路径文件名主干文件后缀为了方便起见我们将文件标识叫文件名。3. 二进制文件和文本文件根据数据的组织形式数据文件被分为二进制文件和文本文件。数据在内存中以二进制的形式存储如果不加转换的输出到外存的文件中就是二进制文件。如果要求在外存上以ASCII码的形式存储则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。一个数据在内存中怎么储存的呢字符⼀律以ASCII形式存储数值型数据既可以用ASCII形式存储也可以使用二进制形式存储。4. 文件的打开和关闭4.1 流和标准流4.1.1 流我们程序的数据需要输出到各种外部设备也需要从外部设备获取数据不同的外部设备的输⼊输出操作各不相同为了方便程序员对各种设备进行方便的操作我们抽象出了流的概念我们可以把流想象成流淌着字符的河。C语言程序对于文件画面键盘等数据都是靠流来进行数据的输入和输出的。我们向流中写入数据或者是读取数据都是要先打开流再进行操作的。4.1.2 标准流那我们平常在从键盘输入数据和向屏幕输出数据都没有进行打开流的步骤这是为什么因为我们在C程序启动的时候会默认打开3个标准流4.2 文件指针我们上面提到了FILE*是文件指针那文件指针指的是什么呢用于存放文件的相关信息。当我们每打开一个文件系统就会根据文件的情况自动创建一个FILE结构的变量并填入信息。一般使用FILE的指针来维护FILE结构变量这样我们使用时也更方便。我们使用文件指针变量能够间接找到与它关联的文件。4.3 文件的打开和关闭我们在打开文件时系统会自动创建FILE结构体又叫开启流也就是前面提到的会将其中的信息存入到其中返回结构体地址给你自己的文件指针变量。注意我们在打开文件时不会自己创建文件指针变量来存放结构体地址文件指针变量由程序员自己创建用于接收打开文件返回的FILE结构体地址。ANSI C规定fopen函数来打开文件fclose来关闭文件。4.3.1 fopen我们来试验一下怎么使用的这些打开的方式有很多种r代表的是“只读”方式打开文件。我们现在只学了打开文件所以这个试验并不完整。以上就是各种打开方式你们记住前三个就差不多了如果后续遇到其他的你们就直接查就行。4.3.2 fclose现在我们学了fclose了应该要学会关闭文件了我们现在将其补充我们在关闭文件之后也一定要记得将文件指针赋值为空指针。5. 文件的顺序读写我们前面对文件的打开方式分了很多种方式那我们对文件进行读写的时候又会涉及一些函数我下面进行一一讲解5.1 fgetc我们来实验一下就会了我们在进行读取之前前提是必须要有这个文件才行fgetc的读取顺序是默认从第一个字符开始往后读并不是随机读取。5.2 fputc我们来试验一下执行成功之后你会发现文件中的内容改变了同时也有输出结果这是因为我们将ch还输出到stdout标准流中也就是直接输出到屏幕上在写入的时候遇到\0就停止了先写入he第二句再写入world。5.3 feof和ferror我们先来测试一下feof:我再文件中放的是abcdef在字符打印完之后继续打印就会显示遇到末尾了如果没有遇到末尾会在标准流上打印字符切记关闭文件之后要记得进行空指针的赋值。我们再来测试一下ferror:上面我们也用到了ferror但是并没有发生读写错误所以并没有使用上。、我们以写的形式打开文件然后读取文件就会发生报错ferror(fp)等于0执行语句这里的运行结果出现了问号是因为控制台编码并不兼容导致还是运行了语句的。perror和ferror都是可以检测错误的而且只有一个字母的差距我们可以进行相关记忆。5.4 fputs这个函数和前面我们刚学的fputc长相相似其根本差异就是一个是将字符写入一个是将字符串写入我们在打印字符和字符串的时候刚好也是一个用c一个用s知道了这两个函数的关联还是很好记忆的。试验fputs遇到\0就结束这就导致我们运行之后就应该是heworld我们看一下文件内容也确实如此。5.5 fgets我们既然有fputs那也确实有fgets。就是从stream中读取num个字符放入到str指向的空间中。不是读取5个字符吗除去\0应该还要读取4个才对为什么全部读取出来了这是因为我们这里有个循环这个循环会反复适应fgets一直往下读一次读取4个末尾会自动补\0num控制单次最多读取字符个数。如果指向读取前5个字符就不使用while循环调用一次就行。5.6 fprintf前面的输入和输出都是字符串但是数据类型并非只有字符和字符串fprintf和printf格式符完全是一样的区别就是printf是打印到屏幕上fprintf是把格式化文本写入文件中。试验1试验2fprintf的参数部分第一个参数是文件指针第二个参数是格式化字符串第三个参数是可变参数部分这其中的后两个参数其实就是printf的两个参数就是增加了一个文件指针。5.7 fscanf试验我们上次使用fprintf后我们已经向文件里面写入了数据我们现在要将数据提取出来不提取出来的话直接使用fprintf是没有数据的。所以我们要将文件中的数据先提取出来才能再次适用fprintf写入到其他地方去。这一对函数都是关联的就好比我们之前的scanf和printf我们可以结合记忆。5.8 fwrite试验5.9 fread试验将文件中的数据提取读取出来rb的以二进制读取文件只读。上面的wb是以二进制写入文件只写。6. 文件的随机读写文件既然有顺序读写自然也就有随机读写。6.1 fseek这三个标识我们一定要记得。试验文件内容是abcdefg这里为什么是使用rb的形式而不使用r的形式我们做随机读写时还是建议使用rb/wb来打开文件。6.2 ftell返回现在的相对偏移量就是用于获取当前文件指针的位置。这个程序可以算文件字节总数偏移量字节数。文件中出现汉字是占2个字节。6.3 rewind试验文件内容abcdefg这其中有疑惑的应该是这个当前位置向前跳2个字节不应该是2吗这是因为fread读取完之后会自动跳过读过的字符我们输出c之后就向后跳了一个位置。7. 总结本文的函数较多但是有很多功能相似函数形态相似的我们可以关联记忆减轻负担本文让我们从代码程序走到文件这是一个漫长的过程从流到文件的打开和关闭再到文件的读写这都是需要我们一步一步来的内容较多篇幅过长还请细细体会。