文件
一个文件可以理解为磁盘上的一段命名的存储区。对于操作系统来说,文件更加复杂,比如大文件可能存储在分散的区段中,或者还会包含一些使操作系统确定文件类型的附加数据等。但是对于C程序员来说不需要考虑底层文件系统的实现,C将文件看出是连续的字节序列,每一个字节都可以单独地存取。 ANSI C提供了文件的两种试图:文本视图和二进制视图。
文本试图和二进制试图是指使用C打开文件的模式,与Windows中的文本文件和二进制文件是两个不同的概念(对C程序来说文本文件和二进制文件没有区别)。使用文本模式打开文件时,会将本地环境表示法映射为C试图,比如 windows 和 Linux有不同的换行模式,但是是用文本模式打开文件时,这两个换行方式都会被映射到 \n
,同样一个C中以 \n
换行的字符串写到文本模式打开的文件时,会自动转换到 \r\n
或者 macintosh 的 \r
。而使用二进制模式打开文件则不会有这样的映射。通常使用文本模式处理二进制文件会效果很糟糕,但是也是可以使用的。
标准输入、输出、错误流是三个特殊的文件,这个已经提到过多次了,它们的fd分贝是0,1,2。
标准IO
之前提到过一篇系统级IO。系统级IO(Unix IO)一般称为低级IO(low level io),使用操作系统提供的基本IO服务,标准IO则是标准C提供的保准所有操作系统都可用的IO模型,ANSI C建立的标准IO模型具有很好的可移植性,我们讨论的标准IO就是它。
除了可以执行之外,标准IO相对于系统级IO还有两个优势:
- 标准IO包含了很多专用的函数,可以方便地处理不同的IO问题。
- 对于输入和输出进行了缓冲,也就是可以大块地转移信息,而不是每次一个字节地转移。
对于标准IO的学习主要就是一些标准IO函数的学习。这些函数本身不是很复杂,只需要大概记住它们的函数声明就可以使用了。这里不一一列举了,写一些比较常用的。
#include <stdio.h> |
第二个参数的打开模式使用一个字符串表示,常用r
, w
, a
, r+
, w+
, a+
,注意使用了w的模式都会删除原有文件的内容。这几个模式都可以再加一个 b 表示使用二进制模式而非文本模式打开文件。不过对于Unix和Linux这样只有一种文件类型的系统,带b和不带b的模式是相同的。
可以看出fopen
和系统级IO的open
返回的不一样,fopen
返回一个方便操作的文件指针fp,而open
是返回一个int类型的fd。指针fp指向一个关于文件信息的数据包,而不是指向实际的文件。
int fgetc(FILE *); |
fgetc 和 getc 的主要区别是 getc是使用宏实现的,而fgetc是一个函数,这意味着一些区别:
- getc的参数不能是一个有副作用的表达式(虽然没有语法错误,但是会很危险)
- 可以获得
fgetc
的地址(函数指针) - 理论上来说,
getc
速度更快,对于大量使用的情况,推荐使用getc
文件的格式化输入输出:
int fprintf(FILE * restrict __stream, const char * restrict __format, ...); |
文件指针操作:
int fseek(FILE * __stream, long int __off, int __whence); // 设置位置指针为指定的值 |
上面的fseek
设定指针的位置是很常见的,其中第二的参数 offset 是一个可正可负可为零(为0用于测试该流是否允许设置指针位置)的long int 类型,第三个参数说明offset 的起始点。 ANSI 中定义了如下起始点常量:
- SEEK_SET 。 文件开始
- SEEK_CUR 。 当前指针
- SEEK_END 。 文件结尾
结合起始点与偏移量可以方便的设置到任意的文件位置。
fgetpos 和 fsetpos 使用一个 fpos_t
类型的指针作为设置值,可以用于更大的文件(超过long int范围长度的文件)。
标准IO内幕
哈哈哈
其他标准IO函数
列出来如下:
int ungetc(int c, FILE *fp)
将指定字符c放回输入流int feof(FILE *fp)
判断是否到达文件结尾int ferror(FILE *fp)
测试错误指示器void clearerr(FILE *)
清楚文件结尾和错误指示器
int setvbuf(FILE * fp, char * buf, int mode, size_t size); |
servbuf可以建立一个供标准IO函数使用的替换缓冲区。(cpp 368)
完
参考: