文件在今天的计算机系统中作用是很重要的。文件用来存放程序、文档、数据、表格、图片和其他很多种类的信息。作为一名程序员,您必须编程来创建、写入和读取文件。编写程序从文件读取信息或者将结果写入文件是一种经常性的需求。C提供了强大的和文件进行通信的方法。使用这种方法我们可以在程序中打开文件,然后使用专门的I/O函数读取文件或者写入文件。
8.1文件相关概念
8.1.1 文件的概念
一个文件通常就是磁盘上一段命名的存储区。但是对于操作系统来说,文件就会更复杂一些。例如,一个大文件可以存储在一些分散的区段中,或者还会包含一些操作系统可以确定其文件类型的附加数据,但是这些是操作系统,而不是我们程序员所要关心的事情。我们应该考虑如何在C程序中处理文件。
8.1.2 流的概念
流是一个动态的概念,可以将一个字节形象地比喻成一滴水,字节在设备、文件和程序之间的传输就是流,类似于水在管道中的传输,可以看出,流是对输入输出源的一种抽象,也是对传输信息的一种抽象。
C语言中,I/O操作可以简单地看作是从程序移进或移出字节,这种搬运的过程便称为流(stream)。程序只需要关心是否正确地输出了字节数据,以及是否正确地输入了要读取字节数据,特定I/O设备的细节对程序员是隐藏的。
8.1.2.1 文本流
文本流,也就是我们常说的以文本模式读取文件。文本流的有些特性在不同的系统中可能不同。其中之一就是文本行的最大长度。标准规定至少允许254个字符。另一个可能不同的特性是文本行的结束方式。例如在Windows系统中,文本文件约定以一个回车符和一个换行符结尾。但是在Linux下只使用一个换行符结尾。
标准C把文本定义为零个或者多个字符,后面跟一个表示结束的换行符(\n).对于那些文本行的外在表现形式与这个定义不同的系统上,库函数负责外部形式和内部形式之间的翻译。例如,在Windows系统中,在输出时,文本的换行符被写成一对回车/换行符。在输入时,文本中的回车符被丢弃。这种不必考虑文本的外部形势而操纵文本的能力简化了可移植程序的创建。
8.1.2.1 二进制流
二进制流中的字节将完全根据程序编写它们的形式写入到文件中,而且完全根据它们从文件或设备读取的形式读入到程序中。它们并未做任何改变。这种类型的流适用于非文本数据,但是如果你不希望I/O函数修改文本文件的行末字符,也可以把它们用于文本文件。
c语言在处理这两种文件的时候并不区分,都看成是字符流,按字节进行处理。
我们程序中,经常看到的文本方式打开文件和二进制方式打开文件仅仅体现在换行符的处理上。
比如说,在widows下,文件的换行符是\r\n,而在Linux下换行符则是\n.
当对文件使用文本方式打开的时候,读写的windows文件中的换行符\r\n会被替换成\n读到内存中,当在windows下写入文件的时候,\n被替换成\r\n再写入文件。如果使用二进制方式打开文件,则不进行\r\n和\n之间的转换。 那么由于Linux下的换行符就是\n,所以文本文件方式和二进制方式无区别。
8.2文件的操作
8.2.1 文件流总览
标准库函数是的我们在C程序中执行与文件相关的I/O任务非常方便。下面是关于文件I/O的一般概况。
|
标准I/O更为简单,因为它们并不需要打开或者关闭。
I/O函数以三种基本的形式处理数据:单个字符、文本行和二进制数据。对于每种形式都有一组特定的函数对它们进行处理。
输入/输出函数家族
家族名 |
目的 |
可用于所有流 |
只用于stdin和stdout |
getchar |
字符输入 |
fgetc、getc |
getchar |
putchar |
字符输出 |
fputc、putc |
putchar |
gets |
文本行输入 |
fgets |
gets |
puts |
文本行输出 |
fputs |
puts |
scanf |
格式化输入 |
fscanf |
scanf |
printf |
格式化输出 |
fprintf |
printf |
8.2.2 文件指针
我们知道,文件是由操作系统管理的单元。当我们想操作一个文件的时候,让操作系统帮我们打开文件,操作系统把我们指定要打开文件的信息保存起来,并且返回给我们一个指针指向文件的信息。文件指针也可以理解为代指打开的文件。这个指针的类型为FILE类型。该类型定义在stdio.h头文件中。通过文件指针,我们就可以对文件进行各种操作。
对于每一个ANSI C程序,运行时系统必须提供至少三个流-标准输入(stdin)、标准输出(stdout)、标准错误(stderr),它们都是一个指向FILE结构的指针。标准输入是缺省情况下的输入来源,标准输出时缺省情况下的输出设置。具体缺省值因编译器而异,通常标准输入为键盘设备、标准输出为终端或者屏幕。
ANSI C并未规定FILE的成员,不同编译器可能有不同的定义。VS下FILE信息如下:
struct _iobuf
{
char *_ptr; //文件输入的下一个位置
int _cnt; //剩余多少字符未被读取
char *_base; //指基础位置(应该是文件的其始位置)
int _flag; //文件标志
int _file; //文件的有效性验证