客户端要实现的功能和服务端相比相对简单,客户端要实现的功能是自动对指定文件中的文件进行备份,也就是定时对指定文件进行扫描,根据文件信息判断文件,符合要求(新文件或者被修改过的文件)进行上传
因此我们客户端大概需要实现下面三个模块
- 数据管理模块:管理备份文件的文件信息,后续需要通过该信息判断文件是否上传
- 目录遍历模块:定时遍历指定文件下的所有文件
- 文件备份模块:遍历文件时,根据文件信息判断是否上传
由于我们客户端大多是给windows用户使用的,因此客户端在Windows上用vs2019进行开发
客户端的实用工具类的实现和服务端是一样的,但是功能少了些,例如压缩解压缩,同时因为vs2019上按照Json库不太方便,因此Json序列化和Json反序列化也不在使用,而在数据管理模块中数据存储时用到的序列化和反序列化,由我们自己完成。
- #ifndef _MY_UTIL_
- #define _MY_UTIL_
- #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING 1
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- namespace mjw_cloud
- {
- 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()
- {
- //这里由于时Windows下,因此目录符号需要改变
- /*int pos = _filename.find_last_of("/");*/
- int pos = _filename.find_last_of("\\");
- if (pos < 0)
- {
- if(!_filename.empty()) return _filename;
- 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
* arry) - {
- CreateDirectory();
- 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 Remove()
- {
- if (Exists() == false)
- {
- std::cout << "object file unexist" << std::endl;
- return false;
- }
- remove(_filename.c_str());
- return true;
- }
-
-
-
- private:
- std::string _filename;
- };
-
- }
-
- #endif