自己封装一个简单的FILE

本文展示了如何创建一个简单的C库,包含自定义的文件操作函数如my_fopen、my_fwrite、my_fflush和my_fclose。这个库使用了一个内部缓冲区来提高效率,减少了对底层IO接口的调用次数。my_fwrite函数考虑了缓冲区满的情况,并根据缓冲策略决定何时刷新。my_fflush用于将缓冲区内容写入文件。整个库的实现加深了对标准C库中FILE结构和缓冲机制的理解。
摘要由CSDN通过智能技术生成

我们学习了系统文件,我们可以对系统接口,模仿库,自己封装一个简单的文件接口,FILE

OK,我们创建文件
在这里插入图片描述
mystdio.h文件内容

   #pragma once                                                                                                    
                                                               
   #include <stdio.h>                                                       
                                                                             
   #define NUM 1024                                                                       
   #define BUFFER_NONE 0x1 // 无缓冲                                               
   #define BUFFER_LINE 0x2 // 行缓冲                                                           
   #define BUFFER_ALL 0x4 // 全缓冲                                                                      
                                                                                               
  typedef struct my_FILE                                                                                 
  {                                                                
    int fd;                                                     
    int flags;                                                                                     
    char outputbuffer[NUM];                                     
    int size;                                                
  }my_FILE;                                                              
                                                                               
  my_FILE* my_fopen(const char* path, const char* mode);                  
  size_t my_fwrite(const void* ptr, size_t size, size_t nmemb, my_FILE* stream);
  int my_fflush(my_FILE* fp);                                                                                      
  int my_fclose(my_FILE* fp); 

my_fopen函数

   my_FILE* my_fopen(const char* path, const char* mode)                                     
  {                                                                                         
    //识别标志位                                                                            
    int flag = 0;                                                                           
    if(strcmp(mode, "r") == 0)                                                              
      flag |= O_RDONLY;                                                                     
    else if(strcmp(mode, "w") == 0)                                                         
      flag |= (O_CREAT | O_WRONLY | O_TRUNC);                                               
    else if(strcmp(mode, "a") == 0)                                                         
      flag |= (O_CREAT | O_WRONLY | O_APPEND);                                              
    else                                                                                    
    {                                                                                       
      //还有"a+","w+","r+"就不一一实现了                                                    
    }                                                                                       
                                                                                            
    //打开文件                                                                              
    mode_t m = 0666;                                                                        
    int fd = 0;                                                                             
    if(flag & O_CREAT) // 如设置了创建的选项,调用三参的open                                
      fd = open(path, flag, m);                                                             
    else                                                                                    
      fd = open(path, flag);                                                                
                                                                                            
    if(fd < 0)                                                                              
      return NULL; // 打开文件失败                                                          
                                                                                            
    // 先创建my_FILE对象,之后返回                                                          
    my_FILE* mf = (my_FILE*)malloc(sizeof(my_FILE));                                        
    if(mf == NULL)                                                                          
    {                                                                                       
      close(fd);//malloc失败了后,要先关闭文件,再返回                                      
      return NULL;                                                                          
    }                                                                                       
                                                                                            
    //初始化对象                                                                            
    mf->fd = fd;
    mf->flags = 0;                                                                            
    mf->flags = BUFFER_LINE;//设置行缓冲                                                    
    memset(mf->outputbuffer, '\0', sizeof(mf->outputbuffer));//初始化缓冲区
  
    //返回打开的文件
    return mf;
  }                      

fflush函数

  int my_fflush(my_FILE* fp)
  {
    assert(fp);
    
    write(fp->fd, fp->outputbuffer, fp->size);
    fp->size = 0;
    return 0;
  }

fwrite函数

  //库函数的返回值是写入的个数,返回写入的个数比较复杂,我们这里返回写入的字节数
  size_t my_fwrite(const void* ptr, size_t size, size_t nmemb, my_FILE* stream)
  {
    //size是数量,nmemb是类型所占的字节数
    if(stream->size == NUM)//缓冲区满了,直接刷新
      my_fflush(stream);
  
    size_t user_size = size * nmemb; // 用户想要写入的字节
    size_t my_size = NUM - stream->size; // 缓冲区剩余的可写入的字节数
  
    size_t writen = 0;//写入的字节数
    if(my_size >= user_size)
    {
      //剩余空间够,用户想写入多少都直接写入
      memcpy(stream->outputbuffer + stream->size, ptr, user_size);
      stream->size += user_size;
      writen = user_size;
    }
    else
    {
      //剩余空间不够,还剩多少写多少
      memcpy(stream->outputbuffer + stream->size, ptr, my_size);
      stream->size += my_size;
      writen = my_size;
    }
  
    //刷新缓冲区
    if(stream->flags & BUFFER_ALL)
    {
      if(stream->size == NUM)
        my_fflush(stream);
    }
    else if(stream->flags & BUFFER_LINE)
    {
      if(stream->outputbuffer[stream->size - 1] == '\n')
        my_fflush(stream);
    }
 
   return 0;
 }

fclose函数

 int my_fclose(my_FILE* fp)
 {
   assert(fp);
   // 冲刷缓冲区
   if(fp->size > 0)
    my_fflush(fp);
   // 关闭文件
   close(fp->fd);
   // 释放空间
   free(fp);
   // 指针置NULL
   fp = NULL;
 
   return 0;
 }

mystdio.c所有代码

    #include "mystdio.h"
    #include <string.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <fcntl.h>
    #include <malloc.h>
    #include <unistd.h>
    #include <assert.h>
   
    my_FILE* my_fopen(const char* path, const char* mode)                                     
  	{                                                                                         
      //识别标志位                                                                            
      int flag = 0;                                                                           
      if(strcmp(mode, "r") == 0)                                                              
        flag |= O_RDONLY;                                                                     
      else if(strcmp(mode, "w") == 0)                                                         
        flag |= (O_CREAT | O_WRONLY | O_TRUNC);                                               
      else if(strcmp(mode, "a") == 0)                                                         
        flag |= (O_CREAT | O_WRONLY | O_APPEND);                                              
      else                                                                                    
      {                                                                                       
        //还有"a+","w+","r+"就不一一实现了                                                    
      }                                                                                       
                                                                                            
      //打开文件                                                                              
      mode_t m = 0666;                                                                        
      int fd = 0;                                                                             
      if(flag & O_CREAT) // 如设置了创建的选项,调用三参的open                                
        fd = open(path, flag, m);                                                             
      else                                                                                    
        fd = open(path, flag);                                                                
                                                                                            
      if(fd < 0)                                                                              
        return NULL; // 打开文件失败                                                          
                                                                                            
      // 先创建my_FILE对象,之后返回                                                          
      my_FILE* mf = (my_FILE*)malloc(sizeof(my_FILE));                                        
      if(mf == NULL)                                                                          
      {                                                                                       
        close(fd);//malloc失败了后,要先关闭文件,再返回                                      
        return NULL;                                                                          
      }                                                                                       
                                                                                             
       //初始化对象                                                                            
       mf->fd = fd;
       mf->flags = 0;                                                                            
       mf->flags = BUFFER_LINE;//设置行缓冲                                                    
       memset(mf->outputbuffer, '\0', sizeof(mf->outputbuffer));//初始化缓冲区
  
       //返回打开的文件
      return mf;
    }                      

     int my_fflush(my_FILE* fp)
     {
       assert(fp);
    
       write(fp->fd, fp->outputbuffer, fp->size);
       fp->size = 0;
       return 0;
     }

    //库函数的返回值是写入的个数,返回写入的个数比较复杂,我们这里返回写入  的字节数
    size_t my_fwrite(const void* ptr, size_t size, size_t nmemb, my_FILE* stream)
    {
      //size是数量,nmemb是类型所占的字节数
      if(stream->size == NUM)//缓冲区满了,直接刷新
        my_fflush(stream);
  
      size_t user_size = size * nmemb; // 用户想要写入的字节
      size_t my_size = NUM - stream->size; // 缓冲区剩余的可写入的字节数
  
      size_t writen = 0;//写入的字节数
      if(my_size >= user_size)
      {
        //剩余空间够,用户想写入多少都直接写入
        memcpy(stream->outputbuffer + stream->size, ptr, user_size);
        stream->size += user_size;
        writen = user_size;
      }
      else
      {
        //剩余空间不够,还剩多少写多少
        memcpy(stream->outputbuffer + stream->size, ptr, my_size);
        stream->size += my_size;
        writen = my_size;
      }
  
      //刷新缓冲区
      if(stream->flags & BUFFER_ALL)
      {
        if(stream->size == NUM)
          my_fflush(stream);
      }
      else if(stream->flags & BUFFER_LINE)
      {
        if(stream->outputbuffer[stream->size - 1] == '\n')
          my_fflush(stream);
      }
 
     return 0;
   }

fclose函数

 int my_fclose(my_FILE* fp)
 {
   assert(fp);
   // 冲刷缓冲区
   if(fp->size > 0)
    my_fflush(fp);
   // 关闭文件
   close(fp->fd);
   // 释放空间
   free(fp);
   // 指针置NULL
   fp = NULL;
 
   return 0;
 }


为什么要c库中还要有个缓冲区呢?

因为文件写入是要调用IO接口的,调用IO是速度比较慢的,c库中有缓冲区,可以减少IO调用次数,加快速度

OK,以上就是简单的封装的FILE了,相信大家看完了之后,对FILE的理解会更加深刻

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值