文件流:
根据应用程序对文件的访问方式,即是否存在缓冲区,对文件的访问可分为带缓冲区的文件操作和非缓冲文件操作。
非缓冲文件访问方式(POSIX标准系统调用函数),每次对文件进行任意一次读写时都需要使用读写文件系统来处理该操作。执行一次系统调用将涉及CPU状态的切换(从用户太到内核态),这会损耗一定的CPU时间,频繁的磁盘访问对程序的执行效率会造成很大影响。
带缓冲区的文件操作(ANSI标准C库函数)建立在底层系统调用之上,采用缓冲机制,这样对磁盘文件进行读操作时可以一次性的从文件中读出大量数据到缓冲区,以后对这部分数据的读写操作就不需要使用系统调用了,从而只需要少量的CPU状态的切换。这样只需要等到文件缓冲区满之后,再调用系统调用将文件一次性写入到磁盘。这种数据的输入输出就像物质的流动一样,在流的视线中,缓冲区是最重要的单元。
每个进程默认可以操作三个流,标准输入流stdin——0(键盘、文件、管道)、标准输出流stdout——1(显示器、文件、管道)、标准错误输出流stderr——2(显示器、文件、管道),每个进程默认从标准输入流读入数据,向标准输出流输出正确信息,向标准错误输出流写入错误信息。
文件流指针(FILE):
在应用编程层面,程序对流的操作体现在文件流操作指针FILE上,使用ANSI标准C库函数fopen()打开一个文件之后,返回一个文件流指针与该文件关联,所有针对该文件的读写操作都通过这个文件流指针来完成。
#include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc,char** argv) { FILE *fp_src,*fp_des; fp_src=fopen(argv[1],"r+"); fp_des=fopen(argv[2],"w+"); char buffer[10]; int i; do { memset(buffer,'\0',10);//buffer中的10个字节用\0替换 i=fread(buffer,1,10,fp_src);//buffer(接受数据的内存地址);1(单个元素的大小-字节);i(元素的个数);fp_des(输入流) fwrite(buffer,1,i,fp_des); } while(i==10); fclose(fp_src); fclose(fp_des); }
测试:判断缓冲区类型:是全缓冲区,行缓冲区还是不带缓冲区
#include <stdio.h> void pr_stdio(const char*,FILE *); //判断缓冲区类型:是全缓冲区,行缓冲区还是不带缓冲区 int main(void) { FILE *fp; fputs("enter any character\n",stdout); if(getchar()==EOF) printf("getchar error"); fputs("one line to standard error\n",stderr); pr_stdio("stdin",stdin);//测试标准输入流 pr_stdio("stdout",stdout);//测试标准输出流 pr_stdio("stderr",stderr);//测试标准错误流 if((fp=fopen("/home/test/motd","r"))==NULL)//以r模式只读,所以文件必须存在 printf("fopen error"); if(fgetc(fp)==EOF) printf("getc error"); pr_stdio("/home/test/motd",fp); return 0; } void pr_stdio(const char *name,FILE *fp) { printf("stream=%s,",name); if(fp->_flags & _IO_UNBUFFERED) printf("unbuffered"); else if(fp->_flags & _IO_LINE_BUF) printf("line buffered"); else printf("fully buffered or modified"); printf(",buffer size=%d\n",fp->_IO_buf_end-fp->_IO_buf_base); }
全缓冲区:只有在调用fclose()时刷新了缓冲区,才会将缓冲区中的数据写入文件(以流的方式)
行缓冲区:以回车为标志,每遇到一次进行一次读写操作,最后遇到fclose()把剩下的写入
不带缓冲区:无缓冲,直接写入文件
下面程序在运行时,可同时打开另一个终端,逐步操作,同时查看到各个文件内容信息
#include <stdio.h> #include <error.h> int main(int argc,char **argv) { int i; FILE *fp; char msg1[]="hello,world\n"; char msg2[]="hello\nworld"; char buf[128]; //打开或者创建一个文件,使用setbuf设置为nobuf情况,并检查关闭当前流的情况 if ((fp=fopen("no_buf.txt","w"))==NULL) { perror("file open failure!"); return -1; } setbuf(fp,NULL);//更改缓冲区类型,第二个参数指向长度为null的缓冲区,即设置为无缓冲区 memset(buf,'\0',128); fwrite(msg1,7,1,fp); printf("now buf data is:buf=%s\n",buf); printf("press enter to continue!\n"); getchar(); fclose(fp); //打开或者创建一个文件,使用setvbuf设置为nobuf情况,并检查关闭当前流的情况 if ((fp=fopen("no_buf2.txt","w"))==NULL) { perror("file open failure!"); return -1; } setvbuf(fp,NULL,_IONBF,0); memset(buf,'\0',128); fwrite(msg1,7,1,fp); printf("now buf data is:buf=%s\n",buf); printf("press enter to continue!\n"); getchar(); fclose(fp); //打开或者创建一个文件,使用setvbuf设置为nobuf情况,并检查关闭当前流的情况 if((fp=fopen("l_buf.txt","w"))==NULL) { perror("file open failure!"); return -1; } setvbuf(fp,buf,_IOLBF,sizeof(buf)); memset(buf,'\0',128); fwrite(msg2,sizeof(msg2),1,fp); printf("now buf data is:buf=%s\n",buf); printf("press enter to continue!\n"); getchar(); fclose(fp); //打开或者创建一个文件,使用setvbuf设置为nobuf情况,并检查关闭当前流的情况 if((fp=fopen("f_buf.txt","w"))==NULL) { perror("file open failure!"); return -1; } setvbuf(fp,buf,_IOFBF,sizeof(buf)); memset(buf,'\0',128); fwrite(msg2,sizeof(msg2),1,fp); printf("now buf data is:buf=%s\n",buf); printf("press enter to continue!\n"); getchar(); fclose(fp); }