文件映射操作类

头文件

MMapFileOperation 类继承自 FileOperation 类,通过继承,子类可以复用基类的文件操作功能。

可以更方便地进行文件的内存映射操作,提供了一套简洁的接口,同时充分利用了继承和组合的思想,重写了父类文件操作类的读写操作,专门用于在内存映射时的读写。

mmap_file_op.h

#ifndef AIRWAVE_LARGEFILE_MMAPFILE_OP_H_
#define AIRWAVE_LARGEFILE_MMAPFILE_OP_H_

#include"common.h"
#include"mmap_file.h"
#include"file_op.h"

namespace Airwave
{
    namespace largefile
    {
        class MMapFileOperation : public FileOperation
        {
        public:
            MMapFileOperation(const std::string& filename, const int open_flags = O_RDWR | O_LARGEFILE | O_CREAT)
                :FileOperation(filename,open_flags),mmap_file_(NULL),is_mmapped_(false)
            {
                //空函数体
            }

            ~MMapFileOperation()
            {
                if (mmap_file_ != NULL)
                {
                    delete mmap_file_;
                    mmap_file_ = NULL;
                }
            }

            int mmap_file(const MMapOption& mmap_option);                                        //将文件映射到内存中,提供映射的参数
            int munmap_file();                                                                   //解除映射

            int pread_file(char* buf,const int32_t size,const int64_t offset);                  //从文件中指定偏移位置读取数据
            int pwrite_file(const char* buf,const int32_t size,const int64_t offset);           //在文件的指定偏移位置写入数据

            void* get_map_data() const;                                                        //获取映射的数据
            int flush_file();                                                                    //把文件立即写入磁盘

        private:
            MMapFile* mmap_file_;               //创建文件映射操作对象
            bool is_mmapped_;                   //是否映射标志
        };
    }





}


#endif // !Airwave_LARGEFILE_MMAPFILE_OP_H_

mmap_file_op.cpp

#include"mmap_file_op.h"
#include"common.h"

static int debug = 1;

namespace Airwave
{
    namespace largefile
    {
        //内存映射
        int MMapFileOperation::mmap_file(const MMapOption& mmap_option)
        {
            if(mmap_option.max_mmap_size_ < mmap_option.first_mmap_size_)       //确保最大映射大于首次映射
            {
                return TFS_ERROR;
            }

            if(mmap_option.max_mmap_size_ <= 0)         //确保最大映射大于0
            {
                return TFS_ERROR;
            }

            int fd = check_file();                  //检查文件是否打开
            if(fd < 0)
            {
                fprintf(stderr, "MMapFileOperation::mmap_file - check_file() failed!");
                return TFS_ERROR;
            }

            if(!is_mmapped_)                         //如果还没有映射
            {
                if(mmap_file_)
                {
                    delete mmap_file_;
                    mmap_file_ = NULL;
                }
                mmap_file_ = new MMapFile(mmap_option, fd);        //创建文件映射操作对象
                is_mmapped_ = mmap_file_->map_file(true);                      //将文件映射到内存,同时设置访问权限
            }

            if (is_mmapped_)
            {
                return TFS_SUCCESS;
            }
            else
            {
                return TFS_ERROR;
            }
        }

        //解除映射
        int MMapFileOperation::munmap_file()
        {
            if(is_mmapped_ && mmap_file_!=NULL)
            {
                delete mmap_file_;
                mmap_file_ = NULL;
                is_mmapped_ = false;
            }
            return TFS_SUCCESS;
        }

        void* MMapFileOperation::get_map_data() const
        {
            if(is_mmapped_)
            {
                return mmap_file_->get_data();
            }
            return NULL;
        }

        //
        int MMapFileOperation::pread_file(char* buf,const int32_t size,const int64_t offset)
        {
            //情况一,内存已经映射
            //如果读取的数据的偏移量大于等于文件在内存中映射的大小
            if(is_mmapped_ && (offset + size)>mmap_file_->get_size())
            {
                if(debug) 
                {
                    fprintf(stdout,"MMapFileOperation::pread_file , size : %d , offset : %ld , map file size : %d, need remap\n" , size, offset,mmap_file_->get_size());
                }
                mmap_file_->remap_file();
            }

            if(is_mmapped_ && (offset + size) <= mmap_file_->get_size())
            {
                memcpy(buf, (char*)mmap_file_->get_data() + offset,size);
                return TFS_SUCCESS;
            }


            //情况二,内存还没有映射,或者要读取的数据映射不全
            return FileOperation::pread_file(buf,size,offset);
        }

        int MMapFileOperation::pwrite_file(const char* buf ,const int32_t size,const int64_t offset)
        {
            //情况一,内存已经映射
            if(is_mmapped_ &&  (offset + size)>mmap_file_->get_size())
            {
                if(debug) 
                {
                    fprintf(stdout,"MMapFileOperation::pread_file , size : %d , offset : %ld , map file size : %d, need remap\n" , size, offset,mmap_file_->get_size());
                }
                mmap_file_->remap_file();
            }   

            if(is_mmapped_ && (offset + size) <= mmap_file_->get_size())
            {
                memcpy((char*)mmap_file_->get_data() + offset,buf,size);
                return TFS_SUCCESS;
            }

            //情况二,内存还没有进行映射,或者映射不全
            return FileOperation::pwrite_file(buf,size,offset);
        }

        int MMapFileOperation::flush_file()
        {
            if(is_mmapped_)
            {
                if(mmap_file_->sync_file())
                {
                    return TFS_SUCCESS;
                }
                else
                {
                    return TFS_ERROR;
                }
            }
            return FileOperation::flush_file();
        }
    }

}

测试 mmap_file_op_test.cpp

#include"common.h"
#include"mmap_file_op.h"
#include<iostream>

using namespace Airwave;
using namespace std;

const static largefile::MMapOption mmap_option = { 10240000, 4096, 4096 };//内存映射参数:最大映射大小、首次映射大小和每次映射增加的大小

int main(void)
{
    int ret = 0;

    const char* filename = "mmap_file_op.txt";
    largefile::MMapFileOperation* mmfo  = new largefile::MMapFileOperation(filename);

    int fd = mmfo->open_file();
    if (fd < 0)
    {
        fprintf(stderr, "open file %s failed. reason : %s\n",filename, strerror(-fd));
        exit(-1);
    }

    ret = mmfo->mmap_file(mmap_option);
    if(ret == largefile::TFS_ERROR)
    {
        fprintf(stderr,"mmap_file failed. reason : %s\n",strerror(errno));
        mmfo->close_file();
        exit(-2);
    }

    char buffer[128 + 1];
    memset(buffer,'6',128);

    ret = mmfo->pwrite_file(buffer,128,8);
    if (ret < 0)
    {
        if(ret == largefile::EIXT_DISK_OPER_INCOMPLETE)
        {
            fprintf(stderr, "pwrite_file %s failed. reason : %s\n",filename, strerror(-ret));
        }
        else
        {
            fprintf(stderr, "pwrite_file %s failed. reason : %s\n",filename, strerror(-ret));
        }
    }
    else
    {
        printf("write file %s success.\n",filename);
    }


       //第一次读取
    memset(buffer, 0, 128);
    ret = mmfo->pread_file(buffer, 128, 8);

    if (ret < 0)
    {
       if(ret == largefile::EIXT_DISK_OPER_INCOMPLETE)
        {
            fprintf(stderr, "read file %s failed. reason : %s\n",filename, strerror(-ret));
        }
        else
        {
            fprintf(stderr, "read file %s failed. reason : %s\n",filename, strerror(-ret));
        }
    }
    else
    {
        buffer[129] = '\0';
        printf("read file %s success. content : %s\n",filename, buffer);
    }

    ret = mmfo->flush_file();
    if(ret == largefile::TFS_ERROR)
    {
        fprintf(stderr,"flush file failed . reason : %s\n",strerror(errno));
    }

    mmfo->munmap_file();

    mmfo->close_file();

    return 0;
}

修改写入的偏移量,测试是否会自动扩容

可以看到超出映射的空间后,文件自动进行映射扩容

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值