1.头文件
#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(); //设计类时要把现实中要实现的接口全部考虑进去,即使这次不用
//方便下次调用时有接口
int pread_file(char*buf,const int32_t nbytes,const int64_t offset);
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_
- .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()); //strdup作用分配一段内存然后把里面的字符串copy过过去
}
FileOperation::~FileOperation()
{
if(fd_>0)
{
::close(fd_); //c++有个规定,如果函数前面带::表示该函数是全局的,防止产生冲突
}
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) //EINTR表示系统繁忙,下次有可能成功
//EAGAIN表示这次是临时出错,叫你继续尝试
{
continue;
}else if(EBADF == -read_len) //EBADF表示文件描述符坏了
{
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) //EINTR表示系统繁忙,下次有可能成功
//EAGAIN表示这次是临时出错,叫你继续尝试
{
continue;
}else if(EBADF == -written_len) //EBADF表示文件描述符坏了
{
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) //EINTR表示系统繁忙,下次有可能成功
//EAGAIN表示这次是临时出错,叫你继续尝试
{
continue;
}else if(EBADF == -written_len) //EBADF表示文件描述符坏了
{
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_);
}
}
}
3.通用头文件
#ifndef _common_H_INCLUDED_
#define _common_H_INCLUDED_
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string>
#include <string.h> //用strerror()函数必须要包含的头文件
#include <stdint.h> //使用int32_t 的头文件
#include <stdio.h> //fprintf()的头文件
#include <errno.h> //使用errno必须包含的要包含的头文件
#include <sys/mman.h> //msync的头文件
#include <unistd.h> //close()函数的头文件
#include <stdlib.h> //free的头文件
namespace qiniu
{
namespace largefile
{
const int32_t EXIT_DISK_OPER_INCOMPLETE = -8012; //读或者写的长度没有满足要求
const int32_t TFS_SUCCESS = 0; //全部读出
}
}
#endif /*_common_H_INCLUDED_*/
4.调试参考代码
```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,1024);
if(ret<0){
if(ret == largefile::EXIT_DISK_OPER_INCOMPLETE){
fprintf(stderr,"pwrite_file: read or write length is less than required!\n");
}else{
fprintf(stderr,"pwrite file %s failed reason:%s\n",filename,strerror(-ret));
}
}
memset(buffer,0,64);
ret = fileOP->pread_file(buffer,64,1024);
if(ret < 0){
if(ret == largefile::EXIT_DISK_OPER_INCOMPLETE){
fprintf(stderr,"pread_file: read or write length is less than required!\n");
}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 or write length is less than required!\n");
}else{
fprintf(stderr,"write_file %s failed reason:%s\n",filename,strerror(-ret));
}
}
fileOP->close_file();
return 0;
}
注释:该代码包含大量的Linux c函数,请在Liunx下调试运行