我们学习了系统文件,我们可以对系统接口,模仿库,自己封装一个简单的文件接口,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的理解会更加深刻