浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第3章 文件I/O(8)_贯穿案例:构建标准IO函数库

Posted on 2017-01-23 22:33  浅墨浓香  阅读(222)  评论(0编辑  收藏  举报

9. 贯穿案例:构建标准IO函数库

//mstdio.h

#ifndef __MSTDIO_H__
#define __MSTDIO_H__

#include <unistd.h>

#define MEOF  -1   //定义文件末尾标志

//文件读写模式
enum mode{READ, WRITE, APPEND};

//MFILE结构体
typedef struct
{
    int     _fd;
    char*   _buffer; //缓冲区
    char*   _nextc;  //下一个字符
    int     _mode;   //读写模式
    off_t   _left;   //剩余多少字节(对于读表示缓冲区中未读的
                     //字节数对于写,表示缓冲区还剩的空闲空间)
}MFILE, *PMFILE;

extern MFILE*   mfopen(const char* const pathname, const char* const mode);
extern int      mfclose(MFILE* fp);
extern void     mfflush(MFILE* fp);
extern MFILE*   mfdopen(int fd, const char* const mode);
extern int      mfgetc(MFILE* fp);
extern int      mfputc(int character, MFILE* fp);
extern int      mungetc(int character, MFILE* fp);
extern char*    mfgets(char* buff, int size, MFILE* fp);
extern int      mfputs(char* buff, MFILE* fp);
extern size_t   mfread(void* buff, size_t size, size_t counter, MFILE* fp);
extern size_t   mfwrite(void* buff, size_t size, size_t counter, MFILE* fp);

#endif

//mstdio.c

#include "mstdio.h"
#include <assert.h>
#include <string.h>
#include <fcntl.h>
#include <malloc.h>

#define BUFFER_LEN  1024

MFILE*   mfopen(const char* const pathname, const char* const mode)
{
    int fd;
    
    if(!strcmp(mode, "r")){
        fd = open(pathname, O_RDONLY);
    }else if(!strcmp(mode, "w")){
        fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, 0777);
    }else if(!strcmp(mode, "a")){
        fd = open(pathname, O_WRONLY | O_CREAT | O_APPEND, 0777);
    }else{
        return NULL;
    }
    
    if (fd < 0)  return NULL;

    return mfdopen(fd, mode);
}

int      mfclose(MFILE* fp)
{
     mfflush(fp);  //先刷新缓存

     int ret = close(fp->_fd);

     free(fp->_buffer);
     free(fp);

     return ret;
}

void     mfflush(MFILE* fp)
{
    if(fp->_mode = READ){
        fp->_nextc = fp->_buffer;
        fp->_left = 0;
    }else{  //WRITE or APPEND
        write(fp->_fd, fp->_buffer, (BUFFER_LEN - fp->_left));
        
        fp->_nextc = fp->_buffer;
        fp->_left = BUFFER_LEN;
    }


}


MFILE*   mfdopen(int fd, const char* const mode)
{
    MFILE* fp = (MFILE*)malloc(sizeof(MFILE));
    assert( fp != NULL);   //断言fp存在
    
    fp->_buffer = (char*)malloc(BUFFER_LEN); //创建缓冲区
    assert(fp->_buffer != NULL);

    fp->_fd = fd;
    fp->_nextc = fp->_buffer;  //初始化,指向缓冲区开始处

    if(!strcmp(mode, "r")){
        fp->_mode = READ;
        fp->_left = 0; //缓冲区剩余0字节未读取,即全部读完。
    }

    if(!strcmp(mode, "w")){
        fp->_mode = WRITE;
        fp->_left = BUFFER_LEN; //缓冲区剩BUFFER_LEN未写,即空的
    }

    if(!strcmp(mode, "a")){
        fp->_mode = APPEND;
        fp->_left = BUFFER_LEN;
    }

    return fp;
}

int      mfgetc(MFILE* fp)
{
    assert(fp->_mode == READ);  //只允许读操作

    //当缓存中的数据己读取完毕,先从文件中读取一批新的数据
    //存入缓存中
    if (fp->_left == 0){
        ssize_t size = read(fp->_fd, fp->_buffer, BUFFER_LEN);

        assert( size >=0 );
        
        if(size == 0) return MEOF;

        fp->_nextc = fp->_buffer;
        fp->_left = size;
    }

    char c = *(fp->_nextc);
    fp->_nextc++;
    fp->_left--;

    return c;
}

int      mfputc(int character, MFILE* fp)
{
    assert(fp->_mode == WRITE || fp->_mode == APPEND);

    //若缓存己满,则先将缓存中的数据写入到文件中
    if(fp->_left == 0){
        if(write(fp->_fd, fp->_buffer, BUFFER_LEN) != BUFFER_LEN){
            return 0;
        }
        
        fp->_nextc = fp->_buffer;
        fp->_left = BUFFER_LEN;
    }

    *(fp->_nextc) = (char)character;
    fp->_nextc++;
    fp->_left--;

    return 1; //返回成功写入的字符个数
}

int      mungetc(int character, MFILE* fp)
{
    int ret = 0;

    return ret;
}

char*    mfgets(char* buff, int size, MFILE* fp)
{
    char* ret = NULL;

    return ret;
}

int      mfputs(char* buff, MFILE* fp)
{
    int ret = 0;

    return ret;
}

size_t   mfread(void* buff, size_t size, size_t counter, MFILE* fp)
{
    size_t ret = 0;

    return ret;
}

size_t   mfwrite(void* buff, size_t size, size_t counter, MFILE* fp)
{
    size_t ret = 0;

    return ret;
}

//mstdio_test.c

#include "mstdio.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int main(int argc, char* argv[])
{

    MFILE* fp1 = mfopen("/etc/passwd", "r");
    assert(fp1 != NULL);

    MFILE* fp2 = mfopen("mypasswd", "w");
    assert( fp2 != NULL);
    
    char c;
    while((c=mfgetc(fp1)) != MEOF){
        mfputc(c, fp2); 
    }

    mfclose(fp1);
    mfclose(fp2);

    return 0;
}