一、文件
文件(file)一般指存储在外部介质上数据的集合,从不同的角度可对文件作不同的分类。根据存储规则可以将其分为mp3、mp4、txt、bmp、jpg、exe、rmvb等文件。从用户的角度看,文件可分为普通文件和设备文件两种:普通文件是指驻留在磁盘或其它外部介质上的一个有序数据集;设备文件是指与主机相联的各种外部设备,如显示器、打印机、键盘等。从文件编码的方式来看,文件可分为ASCII码文件和二进制码文件两种。
ASCII文件也称为文本文件,这种文件在磁盘中存放时每个字符对应一个字节,用于存放对应的ASCII码。比如ini、h、c等文件都是文本文件。例如,数5678的文本存储形式为每个数字的ASCII码:00110101 00110110 00110111 00111000占是个字节。二进制文件是按二进制的编码方式来存放文件的。 例如, 数5678的存储形式为: 00010110 00101110只占二个字节。
二、C语言文件操作
利用C语言进行文件操作的常用方法有三种:
(1)利用C语言的标准库进行文件操作。
(2)在UNIX环境下,可以利用UNIX系统接口,利用open,read,write等低级系统I/O进行文件操作。
(3)在Windows下可以利用fopen_s,fscanf_s等库函数的安全版本进行文件操作。
1、利用C的标准I/O库进行文件操作
<1> 流与文件指针
标准I/O库是围绕流进行的。C语言操作文件可以是字节流或者二进制流。但是C系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。 输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。
标准I/O库打开或创建一个文件时,我们已使一个文件流与一个文件相关联。通过fopen打开一个文件时,会返回一个指向该文件的指针称为文件指针。文件指针指向一个包含文件信息的结构,这些信息包括缓冲区的位置、缓冲区中当前字符的位置、文件的读或写状态、是否出错或是否到达文件结尾等等。文件指针用FILE*来描述
struct _iobuf {
char *_ptr; //文件输入的下一个位置
int _cnt; //剩余的字符数
char *_base; //缓冲区位置
int _flag; //文件访问模式
int _file; //文件的有效性验证
int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
int _bufsiz; //记录缓冲区的大小
char *_tmpfname; //临时文件名
};
typedef struct _iobuf FILE;
对于ASCII码字符集,一个字符用一个字节表示。对于国际字符集,一个字符可用多个字节表示。标准I/O文件流可用于单字节或多字节字符集。流的定向决定了读的是一个单字节或多字节的。当一个流最初被创建时,它并没有定向。如若在未定向的流上使用一个多字节I/O函数(见<wchar.h>),则流的定向设置为宽定向。若在未定向的流上使用一个单字节的I/O函数,则将该流定向为字节定向。
fwide函数可用于设置流的定向。而freopen函数可用于清除一个流的定向。
<wchar.h>
int fwide(
FILE *stream,
int mode;
);
启动一个C语言程序时,操作系统环境会打开标准输入、标准输出和标准错误3个文件,相应的文件指针分别为stdin、stdout和stderr(文件指针stdin/stdout都是FILE*类型的对象,但它们是常量而非变量,不能对它们赋值)。在大多数环境中,stdin指向键盘,而stdout和stderr指向显示器。当然也可以被重定向到文件或者管道。
大多数系统都限制了可以同时打开的文件数。因此不使用时要及时关闭掉文件指针。
< 2 >文件缓冲
标准I/O库提供了缓冲,目的是尽可能的减少使用read和write调用的次数。标准I/O库提供了三种类型的缓冲
1)全缓冲。在填满标准I/O缓冲后才进行实际I/O操作。
2)行缓冲。在输入输出遇到换行符时,标准I/O库执行I/O操作。
行缓冲的限制:①因为标准I/O库用来收集每一行缓冲区的长度是固定的,所以只要填满了缓冲区,那么即使还没有写一个换行符,有进行I/O操作。②任何时候只要通过标准I/O库要求从一个不带缓冲的流或者一个行缓冲的流得到输入数据,那么就会冲洗所有的缓冲输出流。
3)不带缓冲。标准I/O库不对字符进行缓冲存储。
系统默认的缓冲:
1)标准错误不带缓冲
2)若是指向终端的设备的流,则进行行缓冲
3)否则进行全缓冲
[1] 更改缓冲类型和大小
(1) setbuf
1) 函数原型
void setbuf(
FILE *stream,
char *buffer
);
2)参数说明
stream 为已打开的文件指针,并且还没有被读或者写
buffer为缓冲区的地址。缓冲区的大小为BUFSIZE(该常量定义在<stdio.h>中)。
buffer为NULL时,将关闭缓冲
3)说明
通常调用该函数后流就是全缓冲的,但是如果流与一个终端设备相关,那么某些系统也可将其设置为行缓冲的。
(2) setvbuf
1)函数原型
int setvbuf(
FILE* stream,
char* buffer,
int mode,
size_t size
);
2)参数
buffer:如果是全缓冲或者行缓冲则需要指定缓冲区buffer,如果没有指定则标准库会自动为该流分配适当的长度的缓冲区(BUFFSIZ);如果是不带缓冲则忽略buffer
mode:可为_IOFBF 全缓冲;_IOLBF 行缓冲;_IONBF 不带缓冲
size:如果是全缓冲或者行缓冲则2 <= size <= INT_MAX (2147483647);如果不带缓冲则忽略size
3)返回值
成功是返回0;若出错返回非0.
4)示例
#include <stdio.h>
int main( void )
{
char buf[1024];
FILE *stream1, *stream2;
if( ((stream1 = fopen( "data1", "a" )) != NULL) &&
((stream2 = fopen( "data2", "w" )) != NULL) )
{
if( setvbuf( stream1, buf, _IOFBF, sizeof( buf ) ) != 0 )
printf( "Incorrect type or size of buffer for stream1\n" );
else
printf( "'stream1' now has a buffer of 1024 bytes\n" );
if( setvbuf( stream2, NULL, _IONBF, 0 ) != 0 )
printf( "Incorrect type or size of buffer for stream2\n" );
else
printf( "'stream2' now has no buffer\n" );
fclose(stream1);
fclose(stream2);
}
}
运行结果:
[ 2 ] 冲洗缓冲区
在标准I/O库中,冲洗意味着将缓冲区的内容写到磁盘上(缓冲区可能只是部分填满的)。在终端驱动程序方面冲洗表示丢弃已存储在缓冲区中的数据。
(1)fflush
int fflush(
FILE* stream
);
若成功返回0,若出错返回EOF。
< 3 > 利用标准I/O库进行文本文件的读写
之前的博文对利用I/O库进行文本文件的打开,逐个字符读写以及逐行读写进行了详细分析。
利用标准I/O库对文本文件进行读写
<4>C语言中的二进制I/O
2、UNIX环境下,利用UNIX系统接口进行文件I/O操作
3、Windows环境下利用fopen_s,fscanf_s等库函数的安全版本进行文件操作