1.文件
有时,需要程序从文件中读取信息或把信息写入文件,这种程序与文件交互的形式就叫做文件重定向。文件通常是在磁盘或固态硬盘上的一段已命名的存储区。对我们而言,文件就是一个名称,里面有一些信息,但对操作系统而言,文件更复杂,里面涉及一些如何对文件分类、存储、检索等等;对于C而言,文件就是一系列连续的字节,每个字节都能被单独读取,同时C提供两种文件模式:文本模式和二进制模式。
2.文本模式和二进制模式
首先,要区分文本内容和二进制内容、文本文件格式和二进制文件格式,以及文件的文本模式和二进制模式。
所有的存储在计算机中的文件都以二进制存储。但是,如果文件最初使用二进制编码的字符(ASCII或Unicode等)表示文本,该文件就是文本文件,其中包含文本内容。如果文件中的二进制值代表机器语言代码或数值数据或图片或音乐编码,该文件就是二进制文件,其中包含二进制内容。
为了规范文本文件的处理,C提供两种访问文件的途径:二进制模式和文本模式。在二进制模式中,程序可以访问文件的每个字节;而在文本模式中,程序所见的内容和文件的实际内容不同,程序以文本模式读取文件时,把本地文件环境表示的行末尾或文件末尾映射为C模式,如把\r\n转换成\n,而以二进制模式读写文本文件,则不会发生映射,因为二进制模式能访问文件的每个字节。
除了选择文件的模式,大多数情况下,还可以选择I/O的两个级别:底层I/O和标准高级I/O,底层I/O即选择操作系统提供的基本I/O服务,标准高级I/O使用C库的标准包和stdio.h头文件定义,因为无法保证所有的操作系统都使用相同的底层I/O模型,C标准只支持标准I/O包。
与底层I/O相比,标准I/O包除了可移植以外还有两个好处。第一,标准I/O有许多专门的函数,简化了处理不同的I/O问题,如printf的转换输出;第二,输入和输出都是缓冲的,即一次性转换一大块信息(通常至少为512字节)。
3.标准文件
C程序会自动打开3个文件,它们被称为标准输入、标准输出和标准错误输出。在默认情况下,标准输入时系统的普遍输入设备,通常为键盘;标准输出和标准错误输出时系统的普遍输出设备,通常为显示屏。stdio.h头文件把3个文件指针和3个标准文件相关联,C程序会自动打开这3个标准文件,如下
标准文件 | 文件指针 | 通常使用的设备 |
标准输入 | stdin | 键盘 |
标准输出 | stdout | 显示器 |
标注错误输出 | stderr | 显示器 |
这些文件指针都是指向FILE(定义在stdio.h中的派生类型)的指针,所以它们可用作标准I/O函数的参数。
4.标准I/O函数
ANIS C标准库的标准I/O系列有几十个函数,显然无法全部介绍,可以根据自己的需要自行查阅了解。
4.1fopen()函数
该函数声明在stdio.h中。它的第一个参数是一个包含该文件名的字符串地址,第二个参数是一个字符串,指定待打开文件的模式。fopen()的模式字符串如下:
模式字符串 | 含义 |
"r" | 以读模式打开文件 |
"w" | 以写模式打开文件,把现有文件长度截为0;如果文件不存在,则创建一个新文件 |
"a" | 以写模式打开文件,在现有文件末尾添加内容;如果文件不存在,则创建一个新文件 |
"r+" | 以读写模式(更新模式)打开文件 |
"w+" | 以读写模式(更新模式)打开文件,把现有文件长度截为0;如果文件不存在,则创建一个新文件 |
"a+" | 以读写模式(更新模式)打开文件,在现有文件末尾添加内容;如果文件不存在,则创建一个新文件 |
"rb"、"wb"、"ab"、"rb+"、"wb+"、 "ab+"、"r+b"、"w+b"、"a+b" | 与更新模式相同,但是以二进制模式而非文本模式打开文件 |
"wx"、"wbx"、"w+x"、"wb+x"或 "w+bx" | 如果文件存在或以独占模式打开文件,则打开文件失败 |
fopen成功打开文件后将返回文件指针FILE*,FILE是一个定义在stdio.h中的派生类型。文件指针并不指向实际的文件,它指向一个包含文件信息的数据对象,其中包含操作文件的I/O函数所用的缓冲区信息,这涉及操作系统中文件系统的知识。
4.2getc()和putc()函数
getc和putc与getchar和putchar类似,所不同的是getc和putc要指明使用哪一个文件,如ch = getc(fp);
,fp是一个文件指针,即从fp指定的文件中读取一个字符。实际上,getchar使用标准输入的getc来定义,即从标准输入stdin中读取一个字符。putc与此类似。
4.3fclose()函数
fclose(fp)函数关闭fp指定的文件,必要时刷新缓冲区。对于较正式的程序,应该检查是否成功关闭文件,如果关闭成功,fclose函数返回0,否则返回EOF。如果磁盘已满、移动硬盘被移除或出现I/O错误,都会导致fclose函数失败。
5.文件I/O
前面介绍过的I/O函数都类似于文件I/O函数,它们的主要区别是,文件I/O函数要用FILE指针指定待处理文件。
5.1fprintf()和fscanf()函数
与getc和getchar之间的区别相同,fprintf和printf函数之间的区别在于需要用第一个参数指定待处理文件。
5.2fgets()和fputs()函数
以及前面介绍过的fgets和fputs函数。fgets(buf, STLEN, fp);
,buf是char类型数组的名称,STLEN是字符串的大小,fp是指向FILE的指针。fputs(buf, fp);
,buf是字符串的地址,fp用于指定目标文件。