C语言第十三章文件操作
文件操作 学习内容
1、C语言中的流
2、标准输入输出及其重定向
3、文件的分类
4、文件的打开和关闭
5、文件的读写
文件操作的基本规则:打开文件-操作文件-关闭文件
何谓文件(Files)
存储在外部介质上具有名字的一组相关数据的集合
数据一般以文件的形式为用户及应用程序使用
文件1、泛指磁盘文件;2、OS对于例如终端显示器或打印机等设备,以文件形式来管理的。
使用文件后,可以实现程序数据分离,数据共享,实现数据长久的保存
文件存储的方式
建立若干目录(文件夹,directory\folder)
在目录里保存文件
同一级目录里保存的文件不能同名
对使用者而言,只要知道文件的路径(path,全目录)和文件名,就能使用改文件
D:\home\Sunner\main.c
Windows用反斜杠\分割路径
UNIX用斜杠/
文件存储在外存中
外存
内存容量小,容易健忘,掉电即失
外存容量大、断电后数据不丢失,可重复使用,永久保存,不健忘
磁盘(Magnetic disks)
磁盘表面涂有磁性物质
磁性单元的N-S极的两种指向表示0-1
光盘(CD、DVD)
光盘表面有一层特殊介质
介质的高低不平的交替表示0-1
U盘(Flash Memory)
闪存,可用电擦除的ROM
一种电化学存储介质,电流的通断表示0-1
文件的分类
1、按文件的逻辑结构
记录文件--由具有一定结构的记录组成(定长和不定长)
流式文件stream--由一个个字符(字节)数据顺序组成,数据流,字节流
流(stream)--计算机的基础设施infrastruture,类似于现实世界里的水电煤气等基础设施
通过一个流(通常和键盘相关)获得全部的输入
通过另一个流(通常和屏幕相关)写出全部的输出
较大规模的程序:
可能需要额外的流,如磁盘文件、网络端口、打印机等。
C语言中的标准流
stdio.h提供了三种标准流
系统定义三个标准文件,分别对应于终端设备:stdin、stdout、stderr。它们共同构成了计算机的基础设施,是备用的,不能声明、打开和关闭。

scanf(),getchar(),gets()等通过stdin获得输入
printf(),putchar(),puts()等用stdout进行输出
Tips:stdout和stderr在默认情况下都指向屏幕,有和区别呢?
输出到stdout的内容先保存到缓冲区(buffer)
而输出到stderr的内容则直接输出到屏幕
输入/输出重定向 redirection
某些操作系统允许标准输入/输出重定向文件
*DOS和UNIX允许程序从文件获得输入或向文件写数据
这种重定向,程序本身是感觉不到的
输入重定向(Input Redirection)
*D:\>demo< infile.txt
*从终端(键盘)输入数据改成从文件中读入数据
输出重定向(Output Redirection)
D:\>demo > outfile.txt
从终端(显示器)输出数据重定向到文件
文件的分类
2、文件按数据的组织形式可以分为:
文本文件(Text file)
二进制文件(Binary file)
C程序的源代码--文本文件
可执行的C程序--二进制文件
文本文件和二进制文件有什么区别呢?

二进制文件与文本文件的区别:
按照数据在内存中的存储形式(二进制)存储到文件
二进制文件存储的字节不一定表示字符,无需ASCII码表进行字符变换,读写速度快

二进制文件的缺点:
不易阅读,妨碍调试过程
尤其注意可移植性问题:
二进制文件与不同类型的计算机及其存储数据方式相关。
存储int型2字节,4字节?先存高位字节,低位字节?与机器字长、对齐方式alignment以及big-endian/little-endian等相关
总之,二进制文件保存数据,不仅要按照存入时的类型,还要按存入时的格式读出,才能恢复期本来面貌。
公开的标准文件格式
如bmp、tif、gif、jpg和mp3等类型的文件,有大量软件生成和使用这些类型的文件
不公开或加密的文件格式
如Microsoft Word的doc格式就不公开,所以至今没有Word以外的其他软件能完美地读出doc文件
实际上,文件就是一种字节序列,无论何种形式。
对于程序员来说,区分文本文件和二进制文件:
文本文件--按行划分
所以必须用特殊的字符标记行的结尾
某些OS还可能用特殊的字符标记文件的末尾
例如DOS将Ctrl+Z设定为文件的结束符
二进制文件---不是按行划分的,可合法地包含任何字符,故不可能留出文件结束符
文件与流的关系
程序通过文件打开操作将流与设备联系起来,文件打开后,可在程序和文件之间交换数据
由程序在磁盘上建立文件(建立文件)
文件打开后,通过写操作将数据存入该文件(写入数据)
由程序打开磁盘上的某个已有文件,通过读操作将文件中的数据读入内存供程序使用(读取数据)
程序通过文件关闭操作来断开流与文件的联系
文件指针(File Pointer)
C程序中的流的打开和关闭是通过文件指针实现的
文件指针的类型为FILE *
FILE * fp;
--定义了FILE型指针变量*fp,标识一个特定的磁盘文件
--Tips:与文件相关联的每个流都有一个FILE类型的控制结构
定义有关文件操作的信息,用户绝对不应修改
通过文件指针对文件进行操作的时候动态保存的数据结构如下:

文件打开操作

文件打开操作一定要判文件打开是否成功!!

为什么要返回文件指针(句柄,handle)呢?
--以后关闭文件时要用
--因FILE结构较大,传回这个结构的首地址效率比传回整个结构效率高
文件关闭操作
为什么要关闭文件,因为文件的写入操作是将数据写入到缓冲区中的,执行了文件关闭操作后,操作系统会将缓冲区中的最后一部分数据全部flush到文件中,整个时候才能生成一个完整的文件。
各种文件的操作成功与否一定要进行判断!!

文件打开后一定要关闭。否则,可能引起数据丢失,甚至影响其他文件的打开,多数情况下,系统限制同时打开状态的文件总数。因此,打开文件前先关闭无用文件是必要的的。
文件打开方式(mode)

文件操作的常用函数:


按字符读写文件

例:从键盘输入一串字符,转存到磁盘文件上demo.txt

例:将0-127之间的ASCII字符写入demo.bin二进制文件中,并读取该文件内容并显示(用写字板和vc打开)
二进制文件读操作经典代码:

按字符串读写文件

使用fgets的重定向来替换gets,可以防止缓冲区溢出,具有重要意义

按格式读写文件

例:修改例12.7,计算每个学生的4门课程的平均分,将学生的各科成绩及平均分输出到文件score.txt中

例:从上面的文件中score.txt读出每个学生的4门课的平均分,各科成绩及平均分。

注意:读的时候和写的时候的格式要一样
fprintf()最普遍的应用:
1、向标准错误流写出错信息
fprintf(stderr,"Error: file can't be opened\n);
即使用户重定向stdout,向stderr写入的信息也保证会出现在屏幕上
2、输出调试信息,报告程序运行到了哪里,那里的状态是什么
1 int Add(int para1, int para2) 2 { 3 int a, b; 4 fprintf(stderr,"DEBUG: Call foo() with %d and %d\n",para1,para2); 5 a = para1; 6 b = para2; 7 return a*b; 8 }
按数据块来读写文件


例:在前几个实例基础上,计算每个学生的4门课程的平均分,将学生的各科成绩及平均分输出到student.txt中,然后再从文件中读出数据并显示到屏幕上

允许程序在单步中读和写比较大的数据块,虽然可以用于文本流,但主要还是用于二进制流。刚才的例子是用在文本流上。
文件的随机读写
如何实现文件的随机读写呢?
文件从头到尾按字节从0开始顺序编址,用以表示数据的存储位置
文件位置指针(Position pointer,文件位置标记)
-指示打开文件的当前读写位置
-对文件每读写一次,文件指针自动指向下一个读写位置,方便地进行顺序读写
-利用文件定位函数,还可实现随机读写

文件定位
设定文件位置指针的函数
void rewind(FILE *fp);
使文件位置指针重新指向文件的开始位置
long ftell(FILE *fp);
返回当前文件位置指针(相对于文件起始位置的字节偏移量)
int fseek(FILE *fp, long offset, int fromwhere);
改变文件位置指针,实现随机读写。将文件位置指针从fromwhere开始移动offset个字节,指示下一个要读取的数据的位置
fp:指向fopen()打开的文件的指针
offset:位置指针的偏移量(字节数),long 型,加l或L
fromwhere:起始位置 (SEEK_SET或0----文件开始,SEEK_CUR或1----当前位置,SEEK_END或2----文件末尾)
文件缓冲
从磁盘驱动器传出或传入信息,性对较慢
提高读写效率的诀窍----缓冲(buffering)
输出缓冲
--写入文件的数据,实际是存储在内存的缓冲区内
--当缓冲区满或关闭文件时,缓冲区自动”清洗"(写入输出设备)
--主动清洗输出流,用fflush(fp);
输入缓冲
--来自输入设备的数据存在输入缓冲区内
--从缓冲区读数据代替了从设备本身读数据
文件缓冲提高效率的原因所在
--缓冲发生在屏幕的后天,自动完成,如getchar()
--从缓冲区读数据或向缓冲区写数据,几乎不花时间
--仅花时间将缓冲区内容传递给磁盘文件,或反之
--一次性的大块移动比频繁的字符移动快得多
缓冲型和非缓冲型文件系统
缓冲型文件系统
--系统自动在内存中为每个正在使用的文件开辟一个缓冲区,读写文件时,数据先送缓冲区再传给C程序或外存
--利用文件指针标识文件
--缓冲型文件系统中的文件操作,也称高级文件操作
--高级文件操作函数ANSI C定义的文件操作函数,具有跨平台和可移植的能力
非缓冲文件系统
--不自动设置文件缓冲区,缓冲区需由程序员自己设定
--没有文件指针,使用称为文件号的整数来标识文件
| fopen族的函数 | open族的函数 |
| 将很多功能从不同OS的范畴转移到了标准语言库的范畴,实现了以独立于实现的方式来执行I/O |
功能一般由OS直接提供,在不同的OS上有细微差别 |
| 较适合处理文本文件,或结构单一的文件,会为了处理方便而改变一些内容 | 通常能直接反映文件的真是情况,因为它的操作都不假定文件的任何结构 |
| 功能更强大,但效率略逊色 |
本章小结
1、文件的分类
2、文件操作函数
--文件的打开和关闭
--文件的顺序读写
--文件的随机读写
有没有图形的标准函数呢?
标准C没有,编译器可能带有图形库,或者使用第三方提供的图形库,当然也可以自己编写图形库。

浙公网安备 33010602011771号