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;
}
参考资料: