免费app下载win10优化大师官网
博客主页:【夜泉_ly】
本文专栏:【项目日记-云备份】
欢迎点赞👍收藏⭐关注❤️
代码已上传 gitee
目录
- 文件信息结构体
- init 初始化
- 数据管理类
- loadInfo 加载文件信息
- storage 持久化存储文件信息
- update 更新信息
- insert 插入信息
- getInfoByURL 根据url获取文件信息
- getInfoBybackPath 根据路径获取文件信息
- getFileInfo 获取所有文件信息
- 测试
我在之前的博客中,
已经实现了服务端工具类,
和服务端配置信息模块。
本篇将实现的是服务端数据管理模块。
CloudBackup/src/datamanager.hpp
文件信息结构体
为了管理文件,
这里选择的是用一个结构体将文件信息组织起来:
struct FileInfo
{FileInfo() {}FileInfo(const std::string &backPath) { init(backPath); }void init(const std::string &backPath);bool _isPacked;size_t _fsize;time_t _mtime;time_t _atime;std::string _backPath;std::string _packPath;std::string _url;
};
_isPacked
,判断文件是否已经被压缩。
_backPath
,这个就是文件备份的路径,因为最常用,所以也用它来初始化。
_packPath
,这个是文件被压缩后的路径。
_url
,这个是客户端传来的请求路径。
init 初始化
void init(const std::string &backPath)
{FileUtils f(backPath);if (!f.exists()){std::cerr << "FileInfo::init: " << backPath << " not exist\n";return;}_isPacked = false;_fsize = f.getSize();_mtime = f.getMTime();_atime = f.getATime();_backPath = backPath;Config *pc = Config::getInstance();_packPath = pc->getPackDir() + f.getFileName() + pc->getPackfileSuffix();_url = pc->getDownloadPrefix() + f.getFileName();
}
一定要检查路径是否存在!
不存在的话一定要打印传入的路径!
_packPath
为 压缩文件目录 + 文件名 + 后缀
_url
为 请求下载的前缀 + 文件名
数据管理类
我是这样想的,
文件数据是唯一的吧,
数据管理类又是大家都会频繁调用的吧,
那继续用单例吧。
class DataManager
{
private:DataManager();DataManager(const DataManager&) = delete;DataManager& operator=(const DataManager&) = delete;void fileInfoToJson(const FileInfo& fileInfo, Json::Value& cur);void jsonToFileInfo(const Json::Value& root, FileInfo& cur);
public:static DataManager* getInstance();~DataManager();bool loadInfo();bool storage();void update(const FileInfo& info);bool insert(const FileInfo& info);bool getInfoByURL(const std::string& key, FileInfo* pInfo);bool getInfoBybackPath(const std::string& path, FileInfo* pInfo);bool getFileInfo(std::vector<FileInfo>* pArr);private:FileUtils _backupFile;pthread_rwlock_t _rwlock;std::unordered_map<std::string, FileInfo> _hash;private:static DataManager* _instance;static std::mutex _mutex;
};std::mutex DataManager::_mutex;
DataManager* DataManager::_instance = nullptr;
先看成员变量:
-
_backupFile
这个是存备份文件信息的。。文件。。的工具类对象。
主要用于bool storage();
,
因为这个函数每次调用都会设置一下backupFile
的内容。 -
_rwlock
用来解决读写者问题
其中update
、insert
函数,
会修改数据,加写锁,
而getInfoByURL
、getInfoBybackPath
、getFileInfo
函数,
只读取数据,加读锁。
然后然后,为了避免误操作,
我搞了两个类:struct Writer {pthread_rwlock_t *_lock;Writer(pthread_rwlock_t *lock) : _lock(lock) { pthread_rwlock_wrlock(_lock); }~Writer() { pthread_rwlock_unlock(_lock); } };struct Reader {pthread_rwlock_t *_lock;Reader(pthread_rwlock_t *lock) : _lock(lock) { pthread_rwlock_rdlock(_lock); }~Reader() { pthread_rwlock_unlock(_lock); } };
这样就能做到简单的
RAII
了。 -
_hash
,哈希表,
k
为string _url
,v
为struct FileInfo
。
这样的管理,
是为了当用户想要下载一个文件时,
我们可以快速的找到对应文件的信息。
剩下两个静态成员变量,
作用和用法与文件配置类的类似,
就不多说了。
接下来看成员函数:
DataManager() : _backupFile(Config::getInstance()->getBackupFile())
{std::cout << "create DataManager\n";if (pthread_rwlock_init(&_rwlock, nullptr))std::cerr << "DataManager: init _rwlock error\n";std::cout << "DataManager begin loadinfo\n";loadInfo();
}
DataManager(const DataManager&) = delete;
DataManager& operator=(const DataManager&) = delete;
void fileInfoToJson(const FileInfo& fileInfo, Json::Value& cur)
{cur["isPacked"] = fileInfo._isPacked;cur["atime"] = static_cast<Json::Int64>(fileInfo._atime);cur["mtime"] = static_cast<Json::Int64>(fileInfo._mtime);cur["fsize"] = static_cast<Json::Int64>(fileInfo._fsize);cur["packPath"] = fileInfo._packPath;cur["backPath"] = fileInfo._backPath;cur["url"] = fileInfo._url;
}
void jsonToFileInfo(const Json::Value& root, FileInfo& cur)
{cur._isPacked = root["isPacked"].asBool();cur._atime = root["atime"].asInt64();cur._mtime = root["mtime"].asInt64();cur._fsize = root["fsize"].asInt64();cur._packPath = root["packPath"].asString();cur._backPath = root["backPath"].asString();cur._url = root["url"].asString();
}public:
static DataManager* getInstance()
{if (_instance == nullptr) {_mutex.lock();if (_instance == nullptr)_instance = new DataManager();_mutex.unlock();}return _instance;
}~DataManager()
{pthread_rwlock_destroy(&_rwlock);
}
上面这几个,没什么需要注意的。
loadInfo 加载文件信息
bool loadInfo()
{if (!_backupFile.getSize())return false;std::string str;if (!_backupFile.getContent(&str))return false;Json::Value root;if (!JsonUtils::deSerialize(str, &root))return false;for (int i = 0; i < root.size(); i++){FileInfo cur;jsonToFileInfo(root[i], cur);_hash[cur._url] = cur;}return true;
}
前两句检查不写,之后就会喜提报错:
storage 持久化存储文件信息
bool storage()
{Json::Value root;for (const auto &[url, fileInfo] : _hash){Json::Value cur;fileInfoToJson(fileInfo, cur);root.append(cur);}std::string str;JsonUtils::serialize(root, &str);return _backupFile.setContent(str);
}
遍历哈希表,
序列化 fileInfo
中的信息,
append
添加进数组(不这样写loadInfo就不能用root[i])
最后转化为字符串存进 _backupFile
。
update 更新信息
insert 插入信息
bool update(const FileInfo &info)
{Writer w(&_rwlock);_hash[info._url] = info;return storage();
}bool insert(const FileInfo &info)
{Writer w(&_rwlock);_hash[info._url] = info;return storage();
}
Writer w(&_rwlock);
加写锁
getInfoByURL 根据url获取文件信息
bool getInfoByURL(const std::string &key, FileInfo *pInfo)
{Reader r(&_rwlock);if (!pInfo)return false;if (!_hash.count(key))return false;*pInfo = _hash[key];return true;
}
Reader r(&_rwlock);
加读锁
getInfoBybackPath 根据路径获取文件信息
bool getInfoBybackPath(const std::string &path, FileInfo *pInfo)
{Reader r(&_rwlock);if (!pInfo)return false;if (!FileUtils(path).exists())return false;*pInfo = FileInfo(path);return true;
}
Reader r(&_rwlock);
加读锁
getFileInfo 获取所有文件信息
bool getFileInfo(std::vector<FileInfo> *pArr)
{Reader r(&_rwlock);if (!pArr)return false;pArr->clear();for (const auto &[url, Info] : _hash)pArr->push_back(Info);return true;
}
Reader r(&_rwlock);
加读锁
测试
CloudBackup/src/testdatamanager.cpp
#include "datamanager.hpp"int main(int argc, char* argv[])
{using namespace Cloud;if(argc == 3){DataManager::getInstance()->insert(FileInfo(argv[1]));DataManager::getInstance()->insert(FileInfo(argv[2]));std::vector<FileInfo> arr;DataManager::getInstance()->getFileInfo(&arr);for(const auto& e : arr)std::cout << e._backPath << std::endl;}return 0;
}
希望本篇文章对你有所帮助!并激发你进一步探索编程的兴趣!
本人仅是个C语言初学者,如果你有任何疑问或建议,欢迎随时留言讨论!让我们一起学习,共同进步!