一,文件实用类设计实现
不管是客户端还是服务端,文件的传输备份都涉及到文件的读写,包括数据管理信息的持久化也是如此,因此首先设计封装文件操作类,这个类封装完毕之后,则在任意模块中对文件进行操作时都将变的简单化。
我们对文件的操作主要有以下几种,也就是我们文件实用类需要实现的功能
- 获取文件大小
- 获取文件最后一次修改时间(客户端在判断文件是否需要上传时需要用到)
- 获取文件最后一次访问时间(判断文件是否属于热点文件就是通过最后一次访问时间)
- 获取文件路径中的文件名
- 向文件写入数据、获取文件数据
- 获取文件指定位置,指定长度的数据(断点重传功能的实现需要该接口)
- 判断文件是否存在
- 创建文件目录、浏览文件目录
- 压缩文件、解压文件
- 删除文件
设计接口如下
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 ScanDirectory();
//压缩文件&解压文件
bool Compress(const std::string& packname);
bool UnCompress(const std::string& filename);
bool Remove();
private:
std::string _filename;
};
代码实现如下
注意创建目录和浏览目录文件用到了filesystem库,该库使用手册如下所示
Filesystem library - cppreference.com
namespace fs=std::experimental::filesystem;
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 false;
}
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()
{
if(Exists()) return true;
return fs::create_directories(_filename);
}
bool ScanDirectory(std::vector<std::string> *arry)
{
for (auto &i : fs::directory_iterator(_filename))
{
if(fs::is_directory(i)==true)//如果文件是路径名则跳过
{
continue;
}
arry->push_back(fs::path(i).relative_path().string());
}
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;
}
bool Remove()
{
if (Exists() == false)
{
std::cout << "object file unexist" << std::endl;
return false;
}
remove(_filename.c_str());
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"
void Utiltest()
{
// 测试大小,最后修改时间,最后访问时间
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::vector<std::string> vs;
ex.ScanDirectory(&vs);
for(auto v:vs)
{
std::cout<<v<<std::endl;
}
std::cout << "--------------------------------------" << std::endl;
// 序列化
const char *name1 = "张三";
int age1 = 18;
float grade1[3] = {77.1, 64.74, 56.11};
Json::Value val;
val["姓名"] = name1;
val["年龄"] = age1;
val["成绩"].append(grade1[0]);
val["成绩"].append(grade1[1]);
val["成绩"].append(grade1[2]);
std::string str;
mjw_cloud::JsonUtil::Serialize(val, &str);
std::cout << str << std::endl;
std::cout << "--------------------------------------" << std::endl;
Json::Value root;
mjw_cloud::JsonUtil::UnSerialize(str, &root);
const char *name2 = root["姓名"].asCString();
int age2 = root["年龄"].asInt();
float grade2[3] = {0};
grade2[0] = root["成绩"][0].asFloat();
grade2[1] = root["成绩"][1].asFloat();
grade2[2] = root["成绩"][2].asFloat();
std::cout << "姓名:" << name2 << std::endl;
std::cout << "年龄:" << age2 << std::endl;
std::cout << "--------------------------------------" << std::endl;
}
结果如下
二,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;
}
};