文件缓冲区

示例

 

看这段代码的结果:

为什么只有系统调用接口write可以输出呢?这个答案与文件缓冲区有很大的关系。 

原理

每种编程语言都有自己的文件操作接口,以c语言为例:

fprintf() printf fwrite等等c接口,在操作完成后都会将数据放到c语言自己维护的缓冲区中,只有在一定条件下(后面说)才会刷新缓冲区到操作系统的缓冲区,最后由操作系统传给硬件设备,例如磁盘,显示器等。

所以刚才的代码里最后一行,直接将stdout关闭,直接将操作系统缓冲区刷新到硬件设备,而c语言自己的缓冲区由于之前未刷新到操作系统缓冲区,关闭直接就找不到操作系统的缓冲区了,更别提将数据传输到硬件设备上了。

缓冲区什么时候刷新?

缓冲区的刷新分为三种:

无缓冲——直接刷新

行缓冲——直到碰到\n才刷新(显示器)

全缓冲——缓冲区满了才刷新(写文件)

当进程退出时也会刷新缓冲区。

为什么要有缓冲区?

提高效率,将多个数据放到缓冲区一起传输会比单个数据多次传输效率高。就好像快递都是一车一车运送的,而不是一个包裹一个包裹运送的。

配合格式化,当我们向显示器打印一个数字时,例如,printf("%d," 10),最终要显示的其实是两个字符

再次理解缓冲区

为什么重定向输出到文件,c语言文件接口输出的内容被写了两遍?

fork创建子进程,子进程会以写时拷贝的方式创建,缓冲区也不例外(每个进程都有缓冲区),因为是写文件,缓冲都没有刷新, 在进程结束后,每个进程的缓冲区都会刷新到文件中,只有系统调用write写的内容在操作系统缓冲区中,只有一份。

这个代码,如果输出重定向到文件,只会输出write。因为输出到文件是全刷新,后面关闭了stdout,c缓冲区未能刷新到操作系统缓冲区。

如果直接输出到显示器,输出结果为printf,fprintf,fwrite,write。因为输出显示器是行刷新,每次写都会刷新c缓冲区,即使最后关闭stdout也没有影响

模拟实现

代码只是简单模拟部分功能,目的是为了理解原理

//myfile.h
#pragma once
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define MODE 0666
#define SIZE 1024

typedef struct _FILE{
    int _fileno;
    char buffer[SIZE];
    int pos;
}_FILE;

_FILE* _fopen(const char* name, const char* mode);

int _fwrite(const char* s,size_t size,size_t count,_FILE* name);

int _fclose(_FILE* name);
//myfile.c
#include "myfile.h"


_FILE* _fopen(const char* name, const char* mode)
{
    int flag = 0;
    if(strcmp(mode, "w") == 0) flag = O_CREAT|O_WRONLY|O_TRUNC;
    if(strcmp(mode, "r") == 0) flag = O_RDONLY;
    if(strcmp(mode, "a") == 0) flag = O_CREAT|O_WRONLY|O_APPEND;

    int fd = open(name, flag, MODE);
    _FILE* file = (_FILE*)malloc(sizeof(_FILE));
    file->_fileno = fd;
    return file;
}

int _fwrite(const char* s,size_t size,size_t count,_FILE* name)
{
    //模拟行刷新
    if(name->pos + size*count >= SIZE)
        return 0;
    memcpy(name->buffer + name->pos, s, size * count);
    name->pos += size * count;
    if(name->buffer[name->pos-1] == '\n')
    {
        //刷新缓冲区
        ssize_t ret = write(name->_fileno, name->buffer, name->pos);
        if(ret < 0)
        {
            return 0;
        }
    }
}

int _fclose(_FILE* name)
{
    return close(name->_fileno);
}
//main.c
#include "myfile.h"

int main()
{
    _FILE* fp = _fopen("test.txt","a");
    const char* message = "myfile\n";
    _fwrite(message, strlen(message),1,fp);
    _fclose(fp);
    return 0;
}

 

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值