一,文件实用类设计实现
不管是客户端还是服务端,文件的传输备份都涉及到文件的读写,包括数据管理信息的持久化也是如此,因此首先设计封装文件操作类,这个类封装完毕之后,则在任意模块中对文件进行操作时都将变的简单化。
我们对文件的操作主要有以下几种,也就是我们文件实用类需要实现的功能
- 获取文件大小
- 获取文件最后一次修改时间(客户端在判断文件是否需要上传时需要用到)
- 获取文件最后一次访问时间(判断文件是否属于热点文件就是通过最后一次访问时间)
- 获取文件路径中的文件名
- 向文件写入数据、获取文件数据
- 获取文件指定位置,指定长度的数据(断点重传功能的实现需要该接口)
- 判断文件是否存在
- 创建文件目录、获取文件目录
- 压缩文件、解压文件
设计接口如下
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.cstd::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.txtif(_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;}};