本文介绍的是ANSI C标准文件操作管理,由于容易和POSIX IO混淆,特总结一遍。
一:基本概念
1. 数据存储方式区别文件分类
根据数据的存储方式可以将文件分为 二进制文件 和 文本文件。
二进制文件:数据按其在内存中的存储形式原样存放,存储量小,速度快,便于存放中间结果。
文本文件:ASCII文件,每个字节存放一个ASCII码字符,存储量大,速度慢,便于对字符操作。
2. 文件缓冲区
系统为正在使用的文件如果自动开辟了缓冲区,那么这就是缓冲区文件系统,ANSI C就是带缓冲区
的,ANSI C使用了全缓冲,行缓冲,无缓冲三种处理方式。
3. 文件指针
流:操作系统抽象出来的概念,常见的有文件流,字符流,不知道这种表达准不准确。
在应用层面对文件流的访问是通过文件指针FILE来实现的,FILE是ANSI C定义的结构体类型,表示
一个文件的信息。定义在头文件stdio.h中。
二:I/O操作
1. 缓冲区
(1)全缓冲区
要求填满整个缓冲区后才进行I/O系统调用操作。对磁盘文件通常使用全缓冲区访问。第一次执行
I/O操作时,ANSI标准的文件管理系统通过调用函数malloc获得需要使用的缓冲区。默认大小8192。当
一个缓冲区被填满后,系统自动调用刷新操作(flush),即将缓冲区的内容写到磁盘,注意,刷新操作
是一个写操作。如果自己不想等缓冲区满后再写,可以自己调用flush()或fflush()方法将缓冲区的内容
写到磁盘。
(2)行缓冲
当在输入和输出中遇到换行符时,标准I/O库执行I/O系统调用刷新缓冲区。当流涉及到终端时一般使用
行缓冲。行缓冲区的大小是固定的,只要填满了缓冲区即使没有遇到换行符也要刷新缓冲区,行缓冲区的
大小是128字节
(3)无缓冲
标准I/O不对字符进行缓冲。想想也是,一个字符还缓冲个啥啊。另外对于出错流也不缓冲,便于错误信息
尽早显示出来。
(4)缓冲区类型的修改
对于任何一个流都可以人为的修改其缓冲区类型,使用方法setbuf()和setvbuf()
setbuf()
头文件:#include <stdio.h>
原型: void setbuf(FILE *stream, char *buf);
参数: stream:文件指针,即文件流对象的指针
buf :给stream使用的缓冲区,如果设置为NULL,则关闭缓冲区。
返回值:成功返回0,失败返回非0值。
setvbuf()
头文件: #include <stdio.h>
原型: int setvbuf(FILE *stream, char *buf, int mode, size_t size);
参数: stream :文件指针,即文件流对象的指针
buf :给stream使用的缓冲区
mode :缓冲区类型,取值为
_IOFBF 0 //全缓冲
_IOLBF 1 //行缓冲
_IONBF 2 //无缓冲
size :buf的大小
说明:如果指定一个不带缓冲的流,则忽略buf和size参数。
如果指定是全缓冲或行缓冲的,则可以设置buf和size的值,以改变默认值。
返回值:成功返回0,不成功返回非0
2. 打开关闭文件
(1)打开文件
使用fopen方法打开文件
头文件定义: #include <stdio.h>
函数原型 : FILE *fopen(const char *path, const char *mode);
参数说明 : path:要打开的文件名字字符串
mode:打开模式,可选值如下:
r(或rb) 以只读的方式打开,文件必须存在
r+(或rb+) 以可读写的方式打开,文件必须存在
w(或wb) 以只写的方式打开,若文件存在则清空,不存在就创建
w+(或wb+) 以可读写的方式打开文件,若文件存在则清空,不存在就创建
a(或ab) 以只写的方式追加文件,若文件存在则追加在后面,不存在就创建
a+(或ab+) 以可读写的方式追加文件,若文件存在则追加在后面,不存在就创建
使用b作为type的部分是得标准I/O可以区分文本文件和二进制文件,需要操作系统的支持。
返回值 : 成功返回文件指针,失败返回NULL
使用freopen函数打开文件替换当前的一个流对象
头文件: #include <stdio.h>
函数原型:FILE *freopen(const char *path, const char *mode, FILE *stream);
参数说明:前两个参数和fopen一样
stream:要替换的流对象
返回值 :成功返回打开文件的文件指针,失败返回NULL
(2)关闭文件
在完成对流对象的操作后应该关闭流对象,在关闭流对象之前应将缓冲区的内容写到磁盘(这一操作由操作
系统完成)。关闭流对象使用方法fclose完成。
头文件定义: #include <stdio.h>
函数原型 : int fclose(FILE *fp);
参数说明 : fp:要关闭的文件指针
返回值 : 成功返回0,失败返回EOF并设置错误标志位error全局变量。
另外如果要关闭打开的所有流对象,使用方法fcloseall函数,int fcloseall(void),返回值说明和fclose一样。
(3)刷新缓冲区内容
即使缓冲区没有填满也可以刷新缓冲区内容,使用函数fflush().
头文件定义: #include <stdio.h>
函数原型 : int fflush(FILE *stream);
参数说明 : stream:文件指针.
返回值 : 成功返回0,失败返回EOF并设置error全局变量.
使用fopen和fclose函数实现打开和关闭文件实例的程序:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp = NULL;
fp = fopen("./tmp", "r");
if(NULL == fp)
{
printf("fail to open file/n");
return -1;
}
printf("open file successfully!/n");
fclose(fp);
return 0;
}
3. 读写文件
ANSI 标准提供了3种类型的I/O处理函数,包括字符读写,行读写(读写字符串)和块读写
(1)字符读写文件流fgetc和fputc
(2)字符串读写函数fgets和fputs
(3)数据块读写函数fread和fwtrite
(4)格式化读写函数fscanf和fprintf
4. 文件定位
ANSI C提供了rewind和fseek方法来定位文件内部指针.
对于文件的读写和移动使用起来也比较简单,由于时间关系不做详细介绍了.
总结:这两篇笔记将POSIX文件操作和ANSI C文件操作的基本方法大概总结了一下.我觉得它们使用起来都不难,
主要是有时候记不清函数原型,使用的时候还要查手册比较麻烦,其实多使用一下就很方便了.在这之前我写代码时
用到这部分函数还去看书上的原型定义或查LinuxC函数手册,其实根本没必要啊,要使用的时候直接使用man就可以
了,ANSI C的库可以使用man来查看帮助,如man fopen,POSIX的函数可以使用man 2来查看帮助,如man 2 open.简直
太方便了.我感觉现在就没必要将二者做比较了,用到的时候如果想不起来直接man一下就OK了.简单吧,忘了怎么写
就去问男人(man),哈哈...
一:基本概念
1. 数据存储方式区别文件分类
根据数据的存储方式可以将文件分为 二进制文件 和 文本文件。
二进制文件:数据按其在内存中的存储形式原样存放,存储量小,速度快,便于存放中间结果。
文本文件:ASCII文件,每个字节存放一个ASCII码字符,存储量大,速度慢,便于对字符操作。
2. 文件缓冲区
系统为正在使用的文件如果自动开辟了缓冲区,那么这就是缓冲区文件系统,ANSI C就是带缓冲区
的,ANSI C使用了全缓冲,行缓冲,无缓冲三种处理方式。
3. 文件指针
流:操作系统抽象出来的概念,常见的有文件流,字符流,不知道这种表达准不准确。
在应用层面对文件流的访问是通过文件指针FILE来实现的,FILE是ANSI C定义的结构体类型,表示
一个文件的信息。定义在头文件stdio.h中。
二:I/O操作
1. 缓冲区
(1)全缓冲区
要求填满整个缓冲区后才进行I/O系统调用操作。对磁盘文件通常使用全缓冲区访问。第一次执行
I/O操作时,ANSI标准的文件管理系统通过调用函数malloc获得需要使用的缓冲区。默认大小8192。当
一个缓冲区被填满后,系统自动调用刷新操作(flush),即将缓冲区的内容写到磁盘,注意,刷新操作
是一个写操作。如果自己不想等缓冲区满后再写,可以自己调用flush()或fflush()方法将缓冲区的内容
写到磁盘。
(2)行缓冲
当在输入和输出中遇到换行符时,标准I/O库执行I/O系统调用刷新缓冲区。当流涉及到终端时一般使用
行缓冲。行缓冲区的大小是固定的,只要填满了缓冲区即使没有遇到换行符也要刷新缓冲区,行缓冲区的
大小是128字节
(3)无缓冲
标准I/O不对字符进行缓冲。想想也是,一个字符还缓冲个啥啊。另外对于出错流也不缓冲,便于错误信息
尽早显示出来。
(4)缓冲区类型的修改
对于任何一个流都可以人为的修改其缓冲区类型,使用方法setbuf()和setvbuf()
setbuf()
头文件:#include <stdio.h>
原型: void setbuf(FILE *stream, char *buf);
参数: stream:文件指针,即文件流对象的指针
buf :给stream使用的缓冲区,如果设置为NULL,则关闭缓冲区。
返回值:成功返回0,失败返回非0值。
setvbuf()
头文件: #include <stdio.h>
原型: int setvbuf(FILE *stream, char *buf, int mode, size_t size);
参数: stream :文件指针,即文件流对象的指针
buf :给stream使用的缓冲区
mode :缓冲区类型,取值为
_IOFBF 0 //全缓冲
_IOLBF 1 //行缓冲
_IONBF 2 //无缓冲
size :buf的大小
说明:如果指定一个不带缓冲的流,则忽略buf和size参数。
如果指定是全缓冲或行缓冲的,则可以设置buf和size的值,以改变默认值。
返回值:成功返回0,不成功返回非0
2. 打开关闭文件
(1)打开文件
使用fopen方法打开文件
头文件定义: #include <stdio.h>
函数原型 : FILE *fopen(const char *path, const char *mode);
参数说明 : path:要打开的文件名字字符串
mode:打开模式,可选值如下:
r(或rb) 以只读的方式打开,文件必须存在
r+(或rb+) 以可读写的方式打开,文件必须存在
w(或wb) 以只写的方式打开,若文件存在则清空,不存在就创建
w+(或wb+) 以可读写的方式打开文件,若文件存在则清空,不存在就创建
a(或ab) 以只写的方式追加文件,若文件存在则追加在后面,不存在就创建
a+(或ab+) 以可读写的方式追加文件,若文件存在则追加在后面,不存在就创建
使用b作为type的部分是得标准I/O可以区分文本文件和二进制文件,需要操作系统的支持。
返回值 : 成功返回文件指针,失败返回NULL
使用freopen函数打开文件替换当前的一个流对象
头文件: #include <stdio.h>
函数原型:FILE *freopen(const char *path, const char *mode, FILE *stream);
参数说明:前两个参数和fopen一样
stream:要替换的流对象
返回值 :成功返回打开文件的文件指针,失败返回NULL
(2)关闭文件
在完成对流对象的操作后应该关闭流对象,在关闭流对象之前应将缓冲区的内容写到磁盘(这一操作由操作
系统完成)。关闭流对象使用方法fclose完成。
头文件定义: #include <stdio.h>
函数原型 : int fclose(FILE *fp);
参数说明 : fp:要关闭的文件指针
返回值 : 成功返回0,失败返回EOF并设置错误标志位error全局变量。
另外如果要关闭打开的所有流对象,使用方法fcloseall函数,int fcloseall(void),返回值说明和fclose一样。
(3)刷新缓冲区内容
即使缓冲区没有填满也可以刷新缓冲区内容,使用函数fflush().
头文件定义: #include <stdio.h>
函数原型 : int fflush(FILE *stream);
参数说明 : stream:文件指针.
返回值 : 成功返回0,失败返回EOF并设置error全局变量.
使用fopen和fclose函数实现打开和关闭文件实例的程序:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp = NULL;
fp = fopen("./tmp", "r");
if(NULL == fp)
{
printf("fail to open file/n");
return -1;
}
printf("open file successfully!/n");
fclose(fp);
return 0;
}
3. 读写文件
ANSI 标准提供了3种类型的I/O处理函数,包括字符读写,行读写(读写字符串)和块读写
(1)字符读写文件流fgetc和fputc
(2)字符串读写函数fgets和fputs
(3)数据块读写函数fread和fwtrite
(4)格式化读写函数fscanf和fprintf
4. 文件定位
ANSI C提供了rewind和fseek方法来定位文件内部指针.
对于文件的读写和移动使用起来也比较简单,由于时间关系不做详细介绍了.
总结:这两篇笔记将POSIX文件操作和ANSI C文件操作的基本方法大概总结了一下.我觉得它们使用起来都不难,
主要是有时候记不清函数原型,使用的时候还要查手册比较麻烦,其实多使用一下就很方便了.在这之前我写代码时
用到这部分函数还去看书上的原型定义或查LinuxC函数手册,其实根本没必要啊,要使用的时候直接使用man就可以
了,ANSI C的库可以使用man来查看帮助,如man fopen,POSIX的函数可以使用man 2来查看帮助,如man 2 open.简直
太方便了.我感觉现在就没必要将二者做比较了,用到的时候如果想不起来直接man一下就OK了.简单吧,忘了怎么写
就去问男人(man),哈哈...