文件映射操作類的實現

1 文件映射操作類的實現

mmap_file_op.h:

#ifndef QINIU_LARGEFILE_MMAPFILE_OP_H_
#define QINIU_LARGEFILE_MMAPFILE_OP_H_

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

namespace qiniu
{
	namespace largefile
	{
		class MMapFileOperation: public FileOperation
		{
			
			public:
				MMapFileOperation(const std::string& file_name, const int open_flags = O_CREAT | O_RDWR | O_LARGEFILE):
				FileOperation(file_name, open_flags),  map_file_(NULL),  is_mapped_(false)
				{
					
				}
			
				~MMapFileOperation()
				{
					if(map_file_){
						delete(map_file_);
						map_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 sized, const int64_t offset);
			
				void *get_map_data() const ;
				int flush_file();
			
			private:
				MMapFile *map_file_;
				bool is_mapped_;
		};
	}
}

#endif  //QINIU_LARGEFILE_MMAPFILE_OP_H_

mmap_file_op.cpp:

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

static int debug = 1;

namespace qiniu
{
	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){
				return TFS_ERROR;
			}
			
			int fd = check_file();
			if(fd < 0){
				fprintf(stderr,  "MMapFileOperation::mmap_file - checking file failed!");
				return TFS_ERROR;
			}
			
			if(!is_mapped_)
			{
				if(map_file_)
				{
					delete(map_file_);
				}
				map_file_ = new MMapFile(mmap_option, fd);
				is_mapped_ = map_file_->map_file(true);
			}
			
			if(is_mapped_)
			{
				return TFS_SUCCESS;
			}
			else 
			{
				return TFS_ERROR;
			}
		}
		
		int MMapFileOperation::munmap_file()
		{
			if(is_mapped_ && map_file_ != NULL)
			{
				delete(map_file_);
				is_mapped_ = false;
			}
			
			return TFS_SUCCESS;
		}
		
		void *MMapFileOperation::get_map_data() const 
		{
			if(is_mapped_){
				return map_file_->get_data();
			}
			
			return NULL;
		}
		
		int MMapFileOperation::pread_file(char *buf, const int32_t size, const int64_t offset)
		{
			//情況1,內存已經映射
			if(is_mapped_ && (offset + size) >map_file_->get_size())
			{
				if(debug) fprintf(stdout, "MMapFileOperation: pread,size: %d, offset: %" __PRI64_PREFIX "d,map file size: %d. need remap\n",
					size, offset, map_file_->get_size());
				map_file_->remap_file();
			}
			
			if(is_mapped_ && (offset + size) <=map_file_->get_size())
			{
				memcpy(buf, (char *)map_file_->get_data() +offset, size);
				return TFS_SUCCESS;
			}
			
			//情況2,內存沒有映射或是要讀取的數據映射不全
			return FileOperation::pread_file(buf, size, offset);
		}
		
		int MMapFileOperation::pwrite_file(const char* buf, const int32_t size, const int64_t offset)
		{
			//情況1,內存已經映射
			if(is_mapped_ && (offset + size) >map_file_->get_size())
			{
				if(debug) fprintf(stdout, "MMapFileOperation: pwrite,size: %d, offset: %" __PRI64_PREFIX "d,map file size: %d. need remap\n",
					size, offset, map_file_->get_size());
				map_file_->remap_file();
			}
			
			if(is_mapped_ && (offset + size) <=map_file_->get_size())
			{
				memcpy((char *)map_file_->get_data() +offset, buf, size);
				return TFS_SUCCESS;
			}
			
			//情況2,內存沒有映射或是要寫入的數據映射不全
			return FileOperation::pwrite_file(buf, size, offset);
		}
		
		int MMapFileOperation::flush_file()
		{
			if(is_mapped_)
			{
				if(map_file_->sync_file()){
					return TFS_SUCCESS;
				}
				else 
				{
					return TFS_ERROR;
				}
			}
			
			return FileOperation::flush_file();
		}
	}
}

test.cpp:

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

using namespace std;
using namespace qiniu;

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);
	buffer[127]='\n';
	
	ret = mmfo->pwrite_file(buffer, 128, 8);
	if(ret < 0){
		if(ret == largefile::EXIT_DISK_OPER_INCOMPLETE){
			fprintf(stderr, " pwrite_file: read  length is less than required!\n");
		}else {
			fprintf(stderr, "pwrite file %s failed. reason: %s\n", filename, strerror(-ret));
		}
	}
	
	memset(buffer, 0, 128);
	ret = mmfo->pread_file(buffer, 128, 8);
	if(ret < 0){
		if(ret ==  largefile::EXIT_DISK_OPER_INCOMPLETE){
			fprintf(stderr, " pread_file: read  length is less than required!");
		}else {
			fprintf(stderr, "pread file %s failed. reason: %s\n", filename, strerror(-ret));
		}
	}else {
		buffer[128] = '\0';
		printf("read: %s\n", buffer);
	}
	
	ret = mmfo->flush_file();
	if(ret == largefile::TFS_ERROR)
	{
		fprintf(stderr, "flush file failed. reason: %s\n", strerror(errno));
	}
	
	memset(buffer, '8', 128);
	buffer[127]='\n';
	ret = mmfo->pwrite_file(buffer, 128, 4000);	// 即使這裏的偏移量很大,也會自動擴充文件的
	
	mmfo->munmap_file();
	
	mmfo->close_file();
	return 0;
}


參考資料:

  1. C/C++從入門到精通-高級程序員之路【奇牛學院】
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章