一,文件实用类设计实现
不管是客户端还是服务端,文件的传输备份都涉及到文件的读写,包括数据管理信息的持久化也是如此,因此首先设计封装文件操作类,这个类封装完毕之后,则在任意模块中对文件进行操作时都将变的简单化。
我们对文件的操作主要有以下几种,也就是我们文件实用类需要实现的功能
- 获取文件大小
- 获取文件最后一次修改时间(客户端在判断文件是否需要上传时需要用到)
- 获取文件最后一次访问时间(判断文件是否属于热点文件就是通过最后一次访问时间)
- 获取文件路径中的文件名
- 向文件写入数据、获取文件数据
- 获取文件指定位置,指定长度的数据(断点重传功能的实现需要该接口)
- 判断文件是否存在
- 创建文件目录、获取文件目录
- 压缩文件、解压文件
设计接口如下
class FileUtil
{
public:
//获取文件大小
size_t size();
//获取文件最后一次修改时间&最后一次访问时间
time_t LastMTime();
time_t LastATime();
//获取文件路径名中的文件名
std::string FileName();
//向文件写入数据&向文件读取数据
bool SetContent(const std::string& body);
bool GetContent(std::string* body);
//获取文件指定位置指定长度字符串
bool GetPosLen(std::string* body,size_t pos,size_t len);
//判断文件是否存在
bool Exists();
//创建文件目录&获取文件目录
bool CreateDirectory();
bool GetDirectory();
//压缩文件&解压文件
bool Compress(const std::string& packname);
bool UnCompress(const std::string& filename);
private:
std::string _filename;
};
代码实现如下
class FileUtil
{
public:
FileUtil(const std::string& filename)
:_filename(filename)
{}
//获取文件大小
size_t FileSize()
{
struct stat st;
if(stat(_filename.c_str(),&st)<0)
{
std::cout<<"get file attributes failed"<<std::endl;
return -1;
}
return st.st_size;
}
//获取文件最后一次修改时间&最后一次访问时间
time_t LastMTime()
{
struct stat st;
if(stat(_filename.c_str(),&st)<0)
{
std::cout<<"get file attributes failed"<<std::endl;
return -1;
}
return st.st_mtime;
}
time_t LastATime()
{
struct stat st;
if(stat(_filename.c_str(),&st)<0)
{
std::cout<<"get file attributes failed"<<std::endl;
return -1;
}
return st.st_atime;
}
//获取文件路径名中的文件名
//./abc/test.c ->test.c
std::string FileName()
{
int pos=_filename.find_last_of("/");
if(pos<0)
{
std::cout<<"filename error"<<std::endl;
return nullptr;
}
return _filename.substr(pos+1);
}
//获取文件指定位置指定长度字符串
bool GetPosLen(std::string* body,size_t pos,size_t len)
{
std::ifstream ifs(_filename,std::ios::binary);
if(ifs.is_open()==false)
{
std::cout<<"open file failed"<<std::endl;
return false;
}
size_t size=this->FileSize();
if(pos+len>size)
{
std::cout<<"Get filecontent is be illegal"<<std::endl;
return 0;
}
ifs.seekg(pos,ifs.beg);
body->resize(size);
ifs.read(&(*body)[0],len);
if(ifs.good()==false)
{
std::cout<<"read file failed"<<std::endl;
return false;
}
ifs.close();
return true;
}
//向文件写入数据&向文件读取数据
bool SetContent(const std::string& body)
{
std::ofstream ofs(_filename,std::ios::binary);
if(ofs.is_open()==false)
{
std::cout<<"SetContent open file failed"<<std::endl;
return false;
}
ofs.write(&body[0],body.size());
if(ofs.good()==false)
{
std::cout<<"write file failed"<<std::endl;
return false;
}
ofs.close();
return true;
}
bool GetContent(std::string* body)
{
size_t fsize=this->FileSize();
return GetPosLen(body,0,fsize);
}
//判断文件是否存在
bool Exists()
{
struct stat sm;
return stat(_filename.c_str(),&sm)==0;
}
//创建文件目录&获取文件目录
bool CreateDirectory()
{
// ./abc/ab/c.txt
if(_filename.empty()) return false;
if(exists(_filename)) return false;
int pos=0,indox=0;
while(indox<_filename.size())
{
pos=_filename.find_first_of("/\\",indox);
//当pos==npos时,说明pos到indox已经没有/,说该创建最后一个文件,创建完break即可
if(pos==std::string::npos)
{
mkdir(_filename.c_str(),0777);
break;
}
if(!exists(_filename.substr(0,pos))) mkdir(_filename.substr(0,pos).c_str(),0777);
indox=pos+1;
}
return true;
}
bool GetDirectory(std::string* filepath)
{
if(_filename.empty()) return false;
int pos=_filename.find_last_of("/\\");
if(pos==std::string::npos)//pos==npos说明没有找到
{
return false;
}
*filepath=_filename.substr(0,pos+1);
return true;
}
//压缩文件&解压文件
bool Compress(const std::string& packname)
{
//1.读取文件内容
std::string filebody;
if(GetContent(&filebody)==false)
{
std::cout<<"get file body failed"<<std::endl;
return false;
}
//2.压缩获取的内容
std::string packbody;
packbody=bundle::pack(bundle::LZIP,filebody);
//3.将压缩的数据放到压缩包文件中
FileUtil fu(packname);
if(fu.SetContent(packbody)==false)
{
std::cout<<"compress write failed"<<std::endl;
return false;
}
return true;
}
bool UnCompress(const std::string& filename)
{
//1.读取压缩文件内容
std::string packbody;
if(GetContent(&packbody)==false)
{
std::cout<<"get pack file body failed"<<std::endl;
return false;
}
//2.解压读到的内容
std::string filebody;
filebody=bundle::unpack(packbody);
//3.将解压后的内容放入文件中
FileUtil fu(filename);
if(fu.SetContent(filebody)==false)
{
std::cout<<"file write failed"<<std::endl;
return false;
}
return true;
}
private:
//用于类内使用
bool exists(const std::string& filename)
{
struct stat sm;
return stat(filename.c_str(),&sm)==0;
}
private:
std::string _filename;
};
测试代码
#include "util.hpp"
int main()
{
//测试大小,最后修改时间,最后访问时间
mjw_cloud::FileUtil fu("./test1.txt");
std::cout<<fu.FileSize()<<std::endl;
std::cout<<fu.LastMTime()<<std::endl;
std::cout<<fu.LastATime()<<std::endl;
std::cout<<"--------------------------------------"<<std::endl;
//测试获取文件名,文件写入,文件读取
std::cout<<fu.FileName()<<std::endl;
std::string write("hello,word\n");
std::cout<<write<<":";
fu.SetContent(write);
std::string read;
fu.GetContent(&read);
std::cout<<read<<std::endl;
std::cout<<"--------------------------------------"<<std::endl;
//压缩文件,解压文件
fu.Compress("./test1.lzip");
std::cout<<"压缩成功\n"<<std::endl;
fu.UnCompress("./test1_lzip.txt");
std::cout<<"解压成功\n"<<std::endl;
std::cout<<"--------------------------------------"<<std::endl;
//创建目录.获取文件目录
mjw_cloud::FileUtil ex("./a/b/c");
ex.CreateDirectory();
std::string filepath;
ex.GetDirectory(&filepath);
std::cout<<filepath<<std::endl;
std::cout<<"--------------------------------------"<<std::endl;
return 0;
}
结果如下
二,Json实用类实现
该类主要是对Json序列化反序列化的通用代码进行一个封装,减少重复代码的实用
/*util.hpp*/
class JsonUtil
{
public:
static bool Serialize(const Json::Value &root, std::string *str)
{
Json::StreamWriterBuilder swb;
std::shared_ptr<Json::StreamWriter> writer_ptr(swb.newStreamWriter());
std::ostringstream sst;
writer_ptr->write(root, &sst);
*str = sst.str();
return true;
}
static bool UnSerialize(const std::string &str, Json::Value *root)
{
std::string err;
Json::CharReaderBuilder crb;
std::shared_ptr<Json::CharReader> read_ptr(crb.newCharReader());
read_ptr->parse(str.c_str(), str.c_str() + str.size(), root, &err);
return true;
}
};