关注嵌入式安卓物联网行业和人才培养,每天更新,欢迎订阅和留言讨论~~~
作者:自然飞鸟,嵌入式安卓物联网讲师。
Linux文件缓冲区详细信息
a )缓冲机制
根据APP应用程序访问文件的方式,即是否存在缓冲区,对文件的访问可以分为带缓冲区的操作和非缓冲区的操作。
a )带缓冲区的文件操作)高级标准文件I/O操作会自动为用户空间中使用的文件创建内存缓冲区。
b )非缓冲区文件操作)低级文件I/O操作,读写文件时,文件操作的缓冲区不打开,直接通过系统调用操作(读取、写入等)磁盘。 当然,它用于允许在自己的程序中为每个文件设置缓冲区。
解释和比较两种类型的文件操作:
1、非缓冲的文件操作访问方式。 每次对文件进行读写操作时,都需要使用读写系统调用处理该操作。 也就是说,需要执行一次系统调用。 运行一次系统调用,就需要切换CPU状态,即从用户空间切换到内核空间,实现进程上下文切换,这会浪费一定的CPU时间,频繁的磁盘访问会严重影响程序的执行效率
2、ANSI标准c库函数建立在基础系统调用的基础上。 即,在c函数库文件访问函数的安装中使用了低级文件I/O系统调用。 ANSI标准c库中的文件处理函数采用了缓冲机制,以减少系统调用的使用次数,提高效率。 由此,在操作盘文件时能够一次将大量的数据读出到缓冲器中,今后对该部分的访问不需要使用系统调用
b )缓冲型
标准I/O有三种类型的缓冲区。
1、全缓冲:该缓冲方式要求整个缓冲区满后再进行I/O系统调用操作。 磁盘文件的操作通常以全缓冲方式访问。 第一次执行I/O操作时,ANSI标准文件管理函数调用malloc函数以获取要使用的缓冲区,默认大小为8192。
//come from /usr/include/stdio.h
/*默认缓冲器size.* /
#ifndef BUFSIZ
# define bufsiz _ io _ bufsiz//bufsiz全局宏定义
#endif
//come from /usr/include/libio.h
#define _IO_BUFSIZ _G_BUFSIZ
//come from/usr/include/_ g _ config.h
#define _G_BUFSIZ 8192 //实际大小
2、行缓冲区:在这种情况下,输入输出中检测到换行符时,标准I/O库函数会执行系统调用。 如果要操作的流包含终端,则使用例如标准输入、标准输出和行缓冲方式。 由于标准I/O库中每行的缓冲区长度是固定的,因此当缓冲区已满时,即使尚未发生换行符,也会执行I/O系统调用。 默认行缓冲区的大小为1024。
比较以下两个程序可以获得移动缓冲区的大小。
024字节无法打印
024字节开始打印
3、无缓冲区:
无缓冲区是标准I/O库直接调用系统调用,而不缓存字符。 标准错误流stderr通常没有缓冲区,因此可以快速显示错误消息。
注:标准输入和标准输出设备(标准输入流和标准输出流只有在没有交互设备参与时才会被完全缓冲。 标准错误输出设备:标准错误不是全缓冲方式。
c )修改缓冲类型
对于任何流,都可以调用setbuf (和setvbuf )函数来更改缓冲区类型。
1、setbuf
名称:
三足动物
功能:
更改文件流缓冲区的位置
头文件:
#inlcude
函数原形:
语音设置(文件*流,char * buf ) )。
参数:
流操作的流对象,buf中指定的缓冲区
返回值:
成功则返回0,有错误则不为0
此函数的第一个参数必须是要操作的流对象,第二个参数buf必须指向长度为BUFSIZ的缓冲区。 如果将buf设置为NULL,则将关闭缓冲区。 如果执行成功,则返回0,否则返回非零值。
2、setvbuf
名称:
setvbuf
功能:
更改文件流缓冲区的位置
头文件:
#inlcude
函数原形:
(int setvbuf (文件* restrictstream,char *restrict buf,int modes,size_t n ) ) ) ) ) ) ) )
参数:
流操作的流对象、buf指定的缓冲区、mode缓冲区类型,n是指buf的大小
返回值:
成功则返回0,有错误则不为0
这是
函数第一个参数为要操作的流对象;第二个参数buf必须指向一个长为BUFSIZ的缓冲区;第三个参数为缓冲区类型,分别定义如下://come from /usr/include/stdio.h
/* The possibilities for the third argument to 'setvbuf'. */
#define _IOFBF 0 /* Fully buffered.*/ //全缓冲
#define _IOLBF 1 /* Line buffered. */ //行缓冲
#define _IONBF 2 /* No buffering. */ //无缓冲
第四个参数为该buf的大小。如果指定一个不带缓冲区的流,则忽略buf和size参数。
如果指定全缓冲区或行缓冲区,则buf和size可选择地指定一个缓冲区及其长度。如果出现指定该流是带缓冲区的,而buf是NULL,则标准I/O库将自动为该流分配适当长度的缓冲,适当长度指的即是由文件属性数据结构(struct stat)的成员st_blksize所指定的值,如果系统不能为该流决定此值(例如若此流涉及一个设备或一个管道),则分配长度BUFSIZ的缓冲区。
此函数如果执行成功,将返回0,否则返回非0值。
以下是一个修改buf大小写文件的实例程序。其源代码如下:
#include
#include
intmain()
{
int i;
FILE *fp;
char msg1[] = "hello,worldn";
char msg2[] = "hello/nworldn";
char buf[128];
/*打开(或者创建)一个文件,然后使用setbuf设置为nobuf情况,并检查关闭前流的情况*/
if((fp =fopen("no_buf1.txt","w")) == NULL)
{
perror("file open fail");
exit(-1);
}
setbuf(fp,NULL);
fwrite(msg1,7,1,fp);
printf("test setbuf(no buf)!checkno_buf1.txtn");//查看 buf 情况
printf("press enter tocontinue!n");
getchar();
fclose(fp);//关闭流,因此将回写 buf(如果有 buf 的话)
/*打开(或者创建)一个文件,然后使用 setvbuf 设置为 nobuf 情况,并检查关闭前流的情况*/
if((fp =fopen("no_buf2.txt","w")) == NULL)
{
perror("file open failure!");
exit(-1);
}
setvbuf(fp,NULL,_IONBF,0); //设置为无 buf
fwrite(msg1,7,1,fp);
printf("test setbuf(no buf)!checkno_buf1.txtn");//查看 buf 情况
printf("press enter tocontinue!n");
getchar();
fclose(fp);//关闭流,因此将回写 buf ( 如果有 buf 的话)
if((fp =fopen("1_buf.txt","w")) == NULL)
{
perror("fail open file");
exit(-1);
}
setvbuf(fp,buf,_IOLBF,sizeof(buf));//设置为行 buf
fwrite(msg2,sizeof(msg2),1,fp);//写内容
printf("test setvbuf(line buf)!check1_buf.txt,because line buf,only data before enter send to filen");//查看 buf 情况
printf("press enter tocontinue!n");
getchar();
fclose(fp); //关闭流,因此将回写buf
//打开(或者创建)一个文件,然后使用 setvbuf 设置为全 buf情况,并检查关闭前流的情况
if((fp =fopen("f_buf.txt","w")) == NULL)
{
perror("file open failure!");
exit(-1);
}
setvbuf(fp,buf,_IOFBF,sizeof(buf));
for(i = 0;i < 2;i++)
{
fputs(msg1,fp);
}
printf("test setbuf(full buf)! checkf_buf.txtn");
printf("press enter to continue!n");
getchar();
fclose(fp);//关闭流,因此将回写 buf
return 0;
}
其编译过程及运行结果如下:
编译:
运行:
以下内容是在过程中查看各文件内容信息:
[njs@njs]#cat no_buf1.txt
hello,w //写入的7个字符全部写入到文件中
[njs@njs]#cat no_buf2.txt
hello,w //写入的7个字符全部写入到文件中
[njs@njs]#cat l_buf.txt
hello //只有回车前的字符写入
[njs@njs]#cat f_buf.txt //没有任何内容写入
运行过程完成后:
[njs@njs]#cat no_buf1.txt
hello,w //与原来内容一样
[njs@njs]#cat no_buf2.txt
hello,w //与原来内容一样
[njs@njs]#cat l_buf.txt
hello
world //因为调用了fclose()函数,刷新了缓冲区,将world写入
[njs@njs]#cat f_buf.txt
hello
world //因为调用了fclose()函数,刷新了缓冲区,将hello/nworld都写入