文件操作的封裝

1 文件操作的封裝

爲了更加方便對文件進行操作,我們這裏對系統提供的API進行封裝。主要實現在file_op.h和file_op.cpp中。

1.1 代碼實現

file_op.h:

#ifndef QINIU_LARGE_FILE_OP_H_
#define QINIU_LARGE_FILE_OP_H_

#include "common.h"

namespace qiniu
{
		namespace largefile
		{
				class FileOperation
				{
				public:
					FileOperation(const std::string &file_name, const int open_flags = O_RDWR | O_LARGEFILE);
					~FileOperation();
					
					int open_file();
					void close_file();
					
					int flush_file();  //把文件立即寫入到磁盤
					
					int unlink_file(); 
					
					virtual int pread_file(char *buf, const int32_t nbytes, const int64_t offset);
					virtual int pwrite_file(const char *buf,  const int32_t nbytes, const  int64_t offset);  
					
					int write_file(const char *buf, const int32_t nbytes);//seek
					
					int64_t get_file_size();
					
					int ftruncate_file(const int64_t length);
					int seek_file(const int64_t offset);
					
					int get_fd() const 
					{
						return fd_;
					}
					
					protected:
						int fd_;
						int open_flags_;
						char *file_name_;
						
						protected:
						int check_file();
						
					protected:
						static const mode_t  OPEN_MODE = 0644;
						static const int MAX_DISK_TIMES = 5;
	
				};
		}
}

#endif  //QINIU_LARGE_FILE_OP_H_

file_op.cpp:

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


namespace qiniu
{
	namespace largefile
	{
		FileOperation::FileOperation(const std::string &file_name, const int open_flags):
		fd_(-1), open_flags_(open_flags)
		{
			file_name_ = strdup(file_name.c_str());
		}
		
		FileOperation::~FileOperation()
		{
			if(fd_ > 0)
			{
				::close(fd_);
			}
			
			if(NULL != file_name_){
				free(file_name_);
				file_name_ = NULL;
			}
		}
		
		int FileOperation::open_file()
		{
			if(fd_ > 0)
			{
				close(fd_);
				fd_=-1;
			}
			
			fd_ = ::open(file_name_, open_flags_, OPEN_MODE);
			if(fd_ < 0)
			{
				return -errno;
			}
			
			return fd_;
		}
		
		void FileOperation::close_file()
		{
			if(fd_ < 0)
			{
				return;
			}
			
			::close(fd_);
			fd_ = -1;
		}
		
		int FileOperation::pread_file(char *buf, const int32_t nbytes, const int64_t offset)
		{
			int32_t left = nbytes;
			int64_t read_offset = offset;
			int32_t read_len = 0;
			char *p_tmp = buf;
			
			int i = 0;
			
			while( left > 0){
				++i;
				
				if(i >= MAX_DISK_TIMES)
				{
					break;
				}
				
				if(check_file() < 0)
				{
					return -errno;
				}
				
				read_len = ::pread64(fd_, p_tmp, left, read_offset);
				
				if(read_len < 0)
				{
					read_len = -errno;
					
					if(-read_len == EINTR  || EAGAIN == -read_len){
						continue;
					}else if(EBADF == -read_len)
					{
						fd_ = -1;
						continue;
					}else {
						return read_len;
					}
				}else if( 0 == read_len)
				{
					break;
				}
				
				left -= read_len;
				p_tmp += read_len;
				read_offset += read_len;
			}
			
			if(0 != left)
			{
				return EXIT_DISK_OPER_INCOMPLETE;
			}
			
			return TFS_SUCCESS;
		}
		
		int FileOperation::pwrite_file(const char *buf,  const int32_t nbytes, const  int64_t offset)
		{
			int32_t left = nbytes;
			int64_t write_offset = offset;
			int32_t written_len = 0;
			const char *p_tmp = buf;
			
			int i = 0;
			
			while( left > 0){
				++i;
				
				if(i >= MAX_DISK_TIMES)
				{
					break;
				}
				
				if(check_file() < 0)
				{
					return -errno;
				}
				
				written_len = ::pwrite64(fd_, p_tmp, left, write_offset);
				
				if(written_len < 0)
				{
					written_len = -errno;
					
					if(-written_len == EINTR  || EAGAIN == -written_len){
						continue;
					}else if(EBADF == -written_len)
					{
						fd_ = -1;
						continue;
					}else {
						return written_len;
					}
				}
				
				left -= written_len;
				p_tmp += written_len;
				write_offset += written_len;
			}
			
			if(0 != left)
			{
				return EXIT_DISK_OPER_INCOMPLETE;
			}
			
			return TFS_SUCCESS;
			
		}
		
		
		int FileOperation::write_file(const char *buf, const int32_t nbytes)
		{
			int32_t left = nbytes;
			int32_t written_len = 0;
			const char *p_tmp = buf;
			
			int i = 0;
			
			while( left > 0){
				++i;
				
				if(i >= MAX_DISK_TIMES)
				{
					break;
				}
				
				if(check_file() < 0)
				{
					return -errno;
				}
				
				written_len = ::write(fd_, p_tmp, left);
				
				if(written_len < 0)
				{
					written_len = -errno;
					
					if(-written_len == EINTR  || EAGAIN == -written_len){
						continue;
					}else if(EBADF == -written_len)
					{
						fd_ = -1;
						continue;
					}else {
						return written_len;
					}
				}
				
				left -= written_len;
				p_tmp += written_len;
				
			}
				
			if(0 != left)
			{
				return EXIT_DISK_OPER_INCOMPLETE;
			}
			
			return TFS_SUCCESS;
		}
		
		
		int64_t FileOperation::get_file_size()
		{
				int fd = check_file();
				
				if(fd < 0)
				{
					return -1;
				}
				
				struct stat statbuf;
				if( fstat(fd, &statbuf) !=0){
					return -1;
				}
				
				return statbuf.st_size;
			
		}
		
		
		
		int FileOperation::check_file()
		{
			if(fd_ < 0)
			{
				fd_ = open_file();
			}
			
			return fd_;
		}
		
		int FileOperation::ftruncate_file(const int64_t length)
		{
			int fd = check_file();
				
			if(fd < 0)
			{
				return fd;
			}
			
			return ftruncate(fd, length);
			
		}
		
		int FileOperation::seek_file(const int64_t offset)
		{
			int fd = check_file();
				
			if(fd < 0)
			{
				return fd;
			}
			
			return  lseek(fd, offset, SEEK_SET);
			
		}
		
		int FileOperation::flush_file()
		{
			if(open_flags_ & O_SYNC){
				return 0;
			}
			
			int fd=check_file();
			if(fd < 0)
			{
				return fd;
			}
			
			return fsync(fd);
		}
		
		
		int FileOperation::unlink_file()
		{
			close_file();
			return ::unlink(file_name_);
		}
		
		
		
		
	}
}

file_op_test.cpp:

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

using namespace std;
using  namespace qiniu;

int main(void){
	const char * filename = "file_op.txt";
	largefile::FileOperation  *fileOP = new largefile::FileOperation(filename, O_CREAT | O_RDWR | O_LARGEFILE);
	
	int fd = fileOP->open_file();
	if(fd < 0){
		fprintf(stderr, "open file %s failed. reason: %s\n", filename, strerror(-fd));
		exit(-1);
	}
	
	char buffer[65];
	memset(buffer, '8', 64);
	int ret = fileOP->pwrite_file(buffer, 64, 128);
	if(ret < 0){
		if(ret == largefile::EXIT_DISK_OPER_INCOMPLETE){
			fprintf(stderr, " pwrite_file: read  length is less than required!");
		}else {
			fprintf(stderr, "pwrite file %s failed. reason: %s\n", filename, strerror(-ret));
		}
	}
	
	memset(buffer, 0, 64);
	ret = fileOP->pread_file(buffer, 64, 128);
	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[64] = '\0';
		printf("read: %s\n", buffer);
	}
	
	memset(buffer, '9', 64);
	ret = fileOP->write_file(buffer, 64);
	if(ret < 0){
		if(ret ==  largefile::EXIT_DISK_OPER_INCOMPLETE){
			fprintf(stderr, " write_file: read  length is less than required!");
		}else{
			fprintf(stderr, " write_file %s failed. reason: %s\n", filename, strerror(-ret));
		}
	}

	fileOP->close_file();
	
	return 0;
}

參考資料:

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