第10章对文件的输入输出
C语言文件操作(含详细步骤)_zjruiiiiii的博客-CSDN博客_c文件操作
与文件进行通信
有时,需要程序从文件中读取信息或把信息写入文件。这种程序与文件
交互的形式就是文件重定向。这种方法很简单,但是有一定限制。例如,假设要编写一个交互程序,询问用户书名并把完整的书名列表保存在文件中。如果使用重定向,应该类似于:
books > bklist
用户的输入被重定向到 bklist 中。这样做不仅会把不符合要求的文本写
入 bklist,而且用户也看不到要回答什么问题。
C提供了更强大的文件通信方法,可以在程序中打开文件,然后使用特
殊的I/O函数读取文件中的信息或把信息写入文件。在研究这些方法之前,
先简要介绍一下文件的性质。
文件是什么
文件(file)通常是在磁盘或固态硬盘上的一段已命名的存储区。对我
们而言,stdio.h就是一个文件的名称,该文件中包含一些有用的信息。然
而,对操作系统而言,文件更复杂一些。例如,大型文件会被分开储存,或
者包含一些额外的数据,方便操作系统确定文件的种类。然而,这都是操作
系统所关心的,程序员关心的是C程序如何处理文件(除非你正在编写操作
系统)。
C把文件看作是一系列连续的字节,每个字节都能被单独读取。这与UNIX环境中(C的发源地)的文件结构相对应。由于其他环境中可能无法完
全对应这个模型,C提供两种文件模式:文本模式和二进制模式。
文本模式和二进制模式
首先,要区分文本内容和二进制内容、文本文件格式和二进制文件格
式,以及文件的文本模式和二进制模式。
948所有文件的内容都以二进制形式(0或1)储存。但是,如果文件最初使
用二进制编码的字符(例如, ASCII或Unicode)表示文本(就像C字符串那
样),该文件就是文本文件,其中包含文本内容。如果文件中的二进制值代
表机器语言代码或数值数据(使用相同的内部表示,假设,用于long或
double类型的值)或图片或音乐编码,该文件就是二进制文件,其中包含二
进制内容。
UNIX用同一种文件格式处理文本文件和二进制文件的内容。不奇怪,
鉴于C是作为开发UNIX的工具而创建的,C和UNIX在文本中都使用\n(换行
符)表示换行。UNIX目录中有一个统计文件大小的计数,程序可使用该计
数确定是否读到文件结尾。然而,其他系统在此之前已经有其他方法处理文
件,专门用于保存文本。也就是说,其他系统已经有一种与UNIX模型不同
的格式处理文本文件。例如,以前的OS X Macintosh文件用\r (回车符)表
示新的一行。早期的MS-DOS文件用\r\n组合表示新的一行,用嵌入的Ctrl+Z
字符表示文件结尾,即使实际文件用添加空字符的方法使其总大小是256的
倍数(在Windows中,Notepad仍然生成MS-DOS格式的文本文件,但是新的
编辑器可能使用类UNIX格式居多)。其他系统可能保持文本文件中的每一
行长度相同,如有必要,用空字符填充每一行,使其长度保持一致。或者,
系统可能在每行的开始标出每行的长度。
为了规范文本文件的处理,C 提供两种访问文件的途径:二进制模式和
文本模式。在二进制模式中,程序可以访问文件的每个字节。而在文本模式
中,程序所见的内容和文件的实际内容不同。程序以文本模式读取文件时,
把本地环境表示的行末尾或文件结尾映射为C模式。例如,C程序在旧式
Macintosh中以文本模式读取文件时,把文件中的\r转换成\n;以文本模式写
入文件时,把\n转换成\r。或者,C文本模式程序在MS-DOS平台读取文件
时,把\r\n转换成\n;写入文件时,把\n转换成\r\n。在其他环境中编写的文本
模式程序也会做类似的转换。
除了以文本模式读写文本文件,还能以二进制模式读写文本文件。如果
读写一个旧式MS-DOS文本文件,程序会看到文件中的\r 和\n 字符,不会发
生映射(图 13.1 演示了一些文本)。如果要编写旧式 Mac格式、MS-DOS格
949式或UNIX/Linux格式的文件模式程序,应该使用二进制模式,这样程序才能
确定实际的文件内容并执行相应的动作。
虽然C提供了二进制模式和文本模式,但是这两种模式的实现可以相
同。前面提到过,因为UNIX使用一种文件格式,这两种模式对于UNIX实现
而言完全相同。Linux也是如此
关键概念
C程序把输入看作是字节流,输入流来源于文件、输入设备(如键
盘),或者甚至是另一个程序的输出。类似地,C程序把输出也看作是字节
流,输出流的目的地可以是文件、视频显示等。
C 如何解释输入流或输出流取决于所使用的输入/输出函数。程序可以
不做任何改动地读取和存储字节,或者把字节依次解释成字符,随后可以把
这些字符解释成普通文本以用文本表示数字。类似地,对于输出,所使用的
函数决定了二进制值是被原样转移,还是被转换成文本或以文本表示数字。
如果要在不损失精度的前提下保存或恢复数值数据,请使用二进制模式以及
fread()和fwrite()函数。如果打算保存文本信息并创建能在普通文本编辑器查
看的文本,请使用文本模式和函数(如getc()和fprintf())。
要访问文件,必须创建文件指针(类型是FILE *)并把指针与特定文件
名相关联。随后的代码就可以使用这个指针(而不是文件名)来处理该文
件。
要重点理解C如何处理文件结尾。通常,用于读取文件的程序使用一个
循环读取输入,直至到达文件结尾。C 输入函数在读过文件结尾后才会检测
到文件结尾,这意味着应该在尝试读取之后立即判断是否是文件结尾。可以
使用13.2.4节中“设计范例”中的双文件输入模式。
本章小结
对于大多数C程序而言,写入文件和读取文件必不可少。为此,绝大对
数C实现都提供底层I/O和标准高级I/O。因为ANSI C库考虑到可移植性,包
含了标准I/O包,但是未提供底层I/O。
标准 I/O 包自动创建输入和输出缓冲区以加快数据传输。fopen()函数为
标准 I/O 打开一个文件,并创建一个用于存储文件和缓冲区信息的结构。
fopen()函数返回指向该结构的指针,其他函数可以使用该指针指定待处理的
文件。feof()和ferror()函数报告I/O操作失败的原因。
C把输入视为字节流。如果使用fread()函数,C把输入看作是二进制值
并将其储存在指定存储位置。如果使用fscanf()、getc()、fgets()或其他相关函
数,C则将每个字节看作是字符码。然后fscanf()和scanf()函数尝试把字符码
翻译成转换说明指定的其他类型。例如,输入一个值23,%f转换说明会把
23翻译成一个浮点值,%d转换说明会把23翻译成一个整数值,%s转换说明
则会把23储存为字符串。getc()和 fgetc()系列函数把输入作为字符码储存,
将其作为单独的字符保存在字符变量中或作为字符串储存在字符数组中。类
似地,fwrite()将二进制数据直接放入输出流,而其他输出函数把非字符数
据转换成用字符表示后才将其放入输出流。
ANSI C提供两种文件打开模式:二进制和文本。以二进制模式打开文
件时,可以逐字节读取文件;以文本模式打开文件时,会把文件内容从文本
的系统表示法映射为C表示法。对于UNIX和Linux系统,这两种模式完全相
同。
通常,输入函数getc()、fgets()、fscanf()和fread()都从文件开始处按顺序
读取文件。然而, fseek()和ftell()函数让程序可以随机访问文件中的任意位
置。fgetpos()和fsetpos()把类似的功能扩展至更大的文件。与文本模式相
比,二进制模式更容易进行随机访问。
第十章课后习题:
C语言程序设计第五版 谭浩强 第五版课后答案_月已满西楼的博客-CSDN博客_c程序设计谭浩强第五版课后答案
第十章目录回顾
10.1C文件的有关基本知识331
10.1.1什么是文件331
10.1.2文件名332
10.1.3文件的分类332
10.1.4文件缓冲区333
10.1.5文件类型指针333
10.2打开与关闭文件334
10.2.1用fopen函数打开数据文件335
10.2.2用fclose函数关闭数据文件337
10.3顺序读写数据文件338
10.3.1怎样向文件读写字符338
10.3.2怎样向文件读写一个字符串341
10.3.3用格式化的方式读写文本文件345
10.3.4用二进制方式向文件读写一组数据345
10.4随机读写数据文件350
10.4.1文件位置标记及其定位350
10.4.2随机读写353
10.5文件读写的出错检测355