【云备份项目总结】客户端篇

在这里插入图片描述

项目总结

  • 整体回顾
    • util.hpp
    • data.hpp
    • cloud.hpp
  • 代码

客户端的代码与服务端的代码实现有很多相似之处,我们也只编写一个简单的客户端代码。

整体回顾

客户端要实现的功能是:对指定文件夹中的文件自动进行备份上传。但是并不是所有的文件每次都需要上传,我们需要能够判断,哪些文件需要上传,哪些不需要,因此需要将备份的文件信息给管理起来,作为下一次文件是否需要备份的判断。因此需要被管理的信息包含以下:

  1. 文件路径名称
  2. 文件唯一标识:由文件名,最后一次修改时间,文件大小组成的一串信息

所以也需要对文件进行操作的fileutil工具,这个其实与服务端的文件实用工具类颇为相似,直接复制过来即可。

同时也需要对文件进行管理,需要datamanager模块。
在之后就是对文件进行上传的文件备份backup模块

util.hpp

与服务端类似。

namespace fs = std::experimental::filesystem;
class FileUtil {
private:std::string _name;
public:FileUtil(const std::string &name) :_name(name) {}size_t FileSize();time_t LastATime();time_t LastMTime();std::string FileName();bool GetPosLen(std::string *content, size_t pos, size_t len);bool GetContent(std::string *content);bool SetContent(const std::string &content);bool Exists();bool CreateDirectory();bool ScanDirectory(std::vector<std::string> *arry);
};

data.hpp

与服务端的差别是在_table 中的val 存储的值的类型不同,其余的也几乎都相同,都是对文件数据的增查改,对文件数据进行永久化储存,程序运行时的初始化。

class DataManager{
private:std::unordered_map<std::string, std::string> _table;std::string _back_file;
public:DataManager(const std::string back_file);bool InitLoad();//程序运行时加载以前的数据bool Storage();//持久化存储bool Insert(const std::string &key, const std::string &val);bool Update(const std::string &key, const std::string &val);bool GetOneByKey(const std::string &key, std::string *val);
};

cloud.hpp

搭建客户端,然后循环检测被管理目录下的文件是否需要被备份。

#define SRV_IP "1.1.1.1"
#define SRV_PORT 9000class BackUp {private:DataManager *_data;std::string _back_dir;std::string _back_file;bool Upload(const std::string &filename);bool IsCanBeUpload(const std::string &filename);std::string GetFileIdentifier(const std::string &filename);public:BackUp(const std::string &back_dir, const std::string &back_file): _back_dir(back_dir), _back_file(back_file){}bool RunModule();};

需要注意的部分是,在判断文件是否需要被备份时的条件,具体会在代码部分指出。

整个客户端大致就是如此了。

代码

util.hpp

#pragma once
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <memory>
#include <experimental/filesystem>//   FileUtile 工具提供了对文件的增删查改的功能,
//              也提供了对目录的查看功能,和创建目录的功能namespace Cloud
{namespace fs = std::experimental::filesystem;class FileUtil{private:std::string _Filename;public:FileUtil(std::string fname) : _Filename(fname){// std::cout << fname << std::endl;}size_t Filesize() // 提取文件大小{struct stat st;if (stat(_Filename.c_str(), &st) < 0){std::cout << "get Filesize fail"<< std::endl;return 0;}return st.st_size;}std::string Filename() // 提取文件名{// /a/b/文件名size_t pos = _Filename.find_last_of("\\");if (pos == std::string::npos){return _Filename;}return _Filename.substr(pos + 1);}	time_t LastMtime() // 提取文件最后一次的修改时间(文件内容){struct stat st;if (stat(_Filename.c_str(), &st) < 0){std::cout << "get File LastMtime fail"<< 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 LastAtime fail"<< std::endl;return -1;}return st.st_atime;}time_t LastCtime() // 提取文件最后一次的修改时间(文件内容 || 文件属性){struct stat st;if (stat(_Filename.c_str(), &st) < 0){std::cout << "get File LastCtime fail"<< std::endl;return -1;}return st.st_ctime;}bool Remove(){if (this->Exists() == false) {return true;}remove(_Filename.c_str());return true;}bool GetPosLen(std::string &body, size_t pos, size_t len){size_t fsize = this->Filesize();if (pos + len > fsize){std::cout << "get file len is error\n";return false;}std::ifstream ifs;ifs.open(_Filename, std::ios::binary);if (ifs.is_open() == false){std::cout << "read open file failed!\n";return false;}ifs.seekg(pos, std::ios::beg);body.resize(len);ifs.read(&body[0], len);if (ifs.good() == false){std::cout << "get file content failed\n";ifs.close();return false;}ifs.close();return true;}bool GetContent(std::string &body){size_t fsize = this->Filesize();return GetPosLen(body, 0, fsize);}bool SetContent(const std::string &body){std::ofstream ofs;ofs.open(_Filename, std::ios::binary);if (ofs.is_open() == false){std::cout << "write open file failed!\n";return false;}ofs.write(&body[0], body.size());if (ofs.good() == false){std::cout << "write file content failed!\n";ofs.close();return false;}ofs.close();return true;}bool Exists(){return fs::exists(_Filename);}bool CreateDirectory(){if (this->Exists())return true;return fs::create_directories(_Filename);}bool ScanDirectory(std::vector<std::string> &arry){CreateDirectory();for (auto &p : fs::directory_iterator(_Filename)){if (fs::is_directory(p) == true){continue;}// relative_path 带有路径的文件名arry.push_back(fs::path(p).relative_path().string());}return true;}};

data.hpp

#pragma once#include "util.hpp"
#include<unordered_map>
#include<sstream>namespace Cloud 
{#define SEP " "class DataManager {private:std::string _backup_file;   // 存储文件信息的文件std::unordered_map<std::string, std::string> _table; int Split(std::string& str, std::string sep, std::vector<std::string>* arry){int count = 0;size_t pos = 0, idx = 0;while (true){pos = str.find(sep, idx);if (pos == idx){idx += sep.size();continue;}if (pos == std::string::npos){break;}arry->push_back(str.substr(idx, pos - idx));idx = pos + sep.size();count++;}if (idx < str.size()){arry->push_back(str.substr(idx));count++;}return count;}public:DataManager(const std::string& backup_file):_backup_file(backup_file){InitLoad();}bool Storage() {  // 将_table里的文件信息写入 back_file// 1、获取_table的信息std::stringstream ss;for (const auto& a : _table){//2. 将所有信息进行有格式化的组织ss << a.first << SEP << a.second << std::endl;}//3. 写入到 back_file 文件FileUtil fu(_backup_file);fu.SetContent(ss.str());return true;}bool InitLoad() {   // 在DataManager 实列化对象时,将_backup_file 里的文件信息提取到 _table中// 1. 从 file中提取数据 std::string body;FileUtil fu(_backup_file);fu.GetContent(body);// 2. 将数据进行分割,然后放入 _table中。std::vector<std::string> arry;Split(body, "\n", &arry);for (auto& a : arry){std::vector<std::string> tmp;Split(a, SEP, &tmp);if (tmp.size() != 2){continue;}_table[tmp[0]] = tmp[1];}return true;}bool Insert(const std::string& key, const std::string& val) {_table[key] = val;Storage();return true;}bool Update(const std::string& key, const std::string& val) {_table[key] = val;Storage();return true;}bool GetOneByKey(const std::string key, std::string* val) {auto it = _table.find(key);if (it == _table.end()){return false;}*val = it->second;return true;}};}

cloud.hpp

#pragma once#include"httplib.h"
#include"util.hpp"
#include"data.hpp"namespace Cloud {
#define SERVER_IP "60.204.140.244"
#define SERVER_PORT 9090class Backup{private:std::string _back_dir;   //需要管理的目录DataManager* _data;   bool IsNeedUpload(const std::string& filename){// 1. 如果文件未被备份过,则需要进行备份   2. 如果文件被修改过,则需要重新备份FileUtil fu(filename);std::string old_id;if (_data->GetOneByKey(filename, &old_id))   // 查看文件是否被备份{//std::cout << old_id << std::endl;std::string new_id = GetFileIdentifier(filename);if (old_id == new_id){return false;}//一个文件比较大,正在徐徐的拷贝到这个目录下,拷贝需要一个过程,//如果每次遍历则都会判断标识不一致需要上传一个几十G的文件会上传上百次//因此应该判断一个文件一段时间都没有被修改过了,则才能上传// 合理的判断方式应该是判断该文件是否被其他线程占用,是否处于被使用的状态 ,我们采取简单一点的时间判断else{if (time(NULL) - fu.LastMtime() < 10)return false;}}//std::cout << old_id << std::endl;return true;}bool Upload(const std::string& file){// 1. 获取数据FileUtil fu(file);std::string body;fu.GetContent(body);//std::cout << fu.Filename() <<": " << fu.Filesize() << std::endl;// 2. 搭建客户端,填充客户端信息httplib::Client client(SERVER_IP, SERVER_PORT);httplib::MultipartFormData item;item.content = body;item.filename = fu.Filename();item.content_type = "application/octet-stream";   // 表示上传的数据类型为任一数据类型,以二进制形式上传item.name = "file";httplib::MultipartFormDataItems items;items.push_back(item);// 3. 上传文件auto res = client.Post("/Upload", items);if (!res || res->status != 200){return false;}return true;}std::string GetFileIdentifier(const std::string& filename) {// a.txt-fsize-mtimeFileUtil fu(filename);std::stringstream ss;ss << fu.Filename() << "-" << fu.Filesize() << "-" << fu.LastMtime();return ss.str();}public:Backup(const std::string& back_dir, const std::string back_file):_back_dir(back_dir){_data = new DataManager(back_file);}bool RunModel(){while (true){//1. 遍历文件列表,获取信息FileUtil fu(_back_dir);std::vector<std::string> arry;fu.ScanDirectory(arry);//std::cout << arry.size() << std::endl;for (auto& a : arry){//std::cout << a << std::endl;// 获取唯一标识符 ,判断是否需要备份if (IsNeedUpload(a)==true){std::cout << "文件需要上传\n";if (Upload(a) == true){std::cout <<GetFileIdentifier(a) << "文件上传成功\n";_data->Insert(a, GetFileIdentifier(a));}}}Sleep(1000);}return true;}};}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/190474.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css style、css color 转 UIColor

你能看过来&#xff0c;就说明这个问题很好玩&#xff01;IT开发是一个兴趣&#xff0c;更是一个挑战&#xff01;兴趣使你工作有热情。挑战使让你工作充满刺激拉满的状态&#xff01;我们日复一日年复一年的去撸代码&#xff0c;那些普普通通的功能代码&#xff0c;已经厌倦了…

AI 绘画 | Stable Diffusion 高清修复、细节优化

前言 在 Stable Diffusion 想要生成高清分辨率的图片。在文生图的功能里&#xff0c;需要设置更大的宽度和高度。在图生图的功能里&#xff0c;需要设置更大的重绘尺寸或者重绘尺寸。但是设置完更大的图像分辨率&#xff0c;需要更大显存&#xff0c;1024*1024的至少要电脑的空…

Python 框架学习 Django篇 (九) 产品发布、服务部署

我们前面编写的所有代码都是在windows上面运行的&#xff0c;因为我们还处于开发阶段 当我们完成具体任务开发后&#xff0c;就需要把我们开发的网站服务发布给真正的用户 通常来说我们会选择一台公有云服务器比如阿里云ecs&#xff0c;现在的web服务通常都是基于liunx操作系统…

11-13 周一 同济子豪兄CNN卷积神经网络学习记录

11-13 周一 同济子豪兄CNN卷积神经网络学习记录 时间版本修改人描述2023年11月13日14:02:14V0.1宋全恒新建文档2023年11月13日19:05:29V0.2宋全恒完成 大白话讲解卷积神经网络的学习 简介 为了深入理解CNN&#xff0c;进行B站 同济子豪兄深度学习之卷积神经网络的学习. 主要内…

Halcon WPF 开发学习笔记(3):WPF+Halcon初步开发

文章目录 前言在MainWindow.xaml里面导入Halcon命名空间WPF简单调用Halcon创建矩形简单调用导出脚本函数 正确显示匹配效果 前言 本章会简单讲解如何调用Halcon组件和接口&#xff0c;因为我们是进行混合开发模式。即核心脚本在平台调试&#xff0c;辅助脚本C#直接调用。 在M…

实验一 Anaconda安装和使用(Python程序设计实验报告)

实验一 Anaconda安装和使用 一、实验环境 Python集成开发环境IDLE/Anaconda 二、实验目的 1&#xff0e;掌握Windows下Anaconda的安装和配置。 2. 掌握Windows下Anaconda的简单使用&#xff0c;包括IDLE、Jupyter Notebook、Spyder工具的使用。 3. 掌握使用pip管理Python扩展库…

【Python大数据笔记_day04_Hadoop】

分布式和集群 分布式:多台服务器协同配合完成同一个大任务(每个服务器都只完成大任务拆分出来的单独1个子任务) 集群:多台服务器联合起来独立做相同的任务(多个服务器分担客户发来的请求) 注意:集群如果客户端请求量(任务量)多,多个服务器同时处理不同请求(不同任务),如果请求量…

【入门Flink】- 08Flink时间语义和窗口概念

Flink-Windows 是将无限数据切割成有限的“数据块”进行处理&#xff0c;这就是所谓的“窗口”&#xff08;Window&#xff09;。 注意&#xff1a;Flink 中窗口并不是静态准备好的&#xff0c;而是动态创建——当有落在这个窗口区间范围的数据达到时&#xff0c;才创建对应的窗…

IDEA 关闭SpringBoot启动Logo/图标

一、环境 1、SpringBoot 2.6.4 Maven POM格式 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.4</version><relativePath/></parent> 2、IDE…

OpenCV:图像噪点消除与滤波算法

人工智能的学习之路非常漫长&#xff0c;不少人因为学习路线不对或者学习内容不够专业而举步难行。不过别担心&#xff0c;我为大家整理了一份600多G的学习资源&#xff0c;基本上涵盖了人工智能学习的所有内容。点击下方链接,0元进群领取学习资源,让你的学习之路更加顺畅!记得…

【hcie-cloud】【3】华为云Stack规划设计之华为云Stack交付综述【上】

文章目录 前言华为云Stack交付综述交付流程华为云Stack交付流程华为云Stack安装部署流程 交付工具链华为云Stack交付工具链eDesigner - 让解决方案销售更智能eDesigner配置页面 - 基本信息eDesigner配置页面 - 服务及组网配置eDesigner配置页面 - 弹性云服务器/ECSeDesigner配置…

带头双向循环链表

文章目录 概述初始化销毁插入删除遍历打印 概述 带头双向循环链表&#xff1a;结构最复杂&#xff0c;一般用在单独存储数据。实际中使用的链表数据结构&#xff0c;都是带头双向循环链表。另外这个结构虽然结构复杂&#xff0c;但是使用代码实现以后会发现结构会带来很多优势…

11.读取文件长度-fseek和ftell函数的使用

文章目录 简介1. 写入测试文件2. 读取文件长度 简介 主要讲使用fopen读取文件&#xff0c;配合使用fseek和ftell来读取文件长度。1. 写入测试文件 执行下方程序&#xff0c;使用fwrite函数写入40字节的数据&#xff0c;使其形成文件存入本地目录。#define _CRT_SECURE_NO_WARNI…

CCF ChinaSoft 2023 论坛巡礼 | 编译技术与编译器设计论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

JVS低代码表单自定义按钮的使用说明和操作示例

在普通的表单设计中&#xff0c;虽然自带的【提交】、【重置】、【取消】按钮可以满足基本操作需求&#xff0c;但在面对更多复杂的业务场景时&#xff0c;这些按钮的显示控制就显得有些力不从心。为了更好地满足用户在表单操作过程中的个性化需求&#xff0c;JVS低代码推出了表…

接口测试--知识问答

1 做接口测试当请求参数多时tps下降明显&#xff0c;此接口根据参数从redis中获取数据&#xff0c;每个参数与redis交互一次&#xff0c;当一组参数是tps5133&#xff0c;五组参数是tps1169&#xff0c;多次交互影响了处理性能&#xff0c;请详细阐述如何改进增进效果的方案。 …

软件外包开发的需求表达方法

软件开发需求的有效表达对于项目的成功至关重要。无论选择哪种需求表达方法&#xff0c;清晰、详细、易于理解是关键。与开发团队建立良好的沟通渠道&#xff0c;确保他们对需求有充分的理解&#xff0c;并随着项目的推进及时调整和更新需求文档。以下是一些常用的需求表达方法…

Django下的Race Condition漏洞

目录 环境搭建 无锁无事务的竞争攻击复现 无锁有事务的竞争攻击复现 悲观锁进行防御 乐观锁进行防御 环境搭建 首先我们安装源码包&#xff1a;GitHub - phith0n/race-condition-playground: Playground for Race Condition attack 然后将源码包上传到Ubuntu 为了方便使…

【Linux】虚拟机连不上外网 (ping www.baidu.com不通)

进入linux系统&#xff0c;打开终端&#xff0c;ping www.baidu.com 发现ping不通 首先我连接的是nat模式 查看是否连接上自己本机的网 切换root用户 使用 ifconfig 命令查看是eth0 还是 ens33 vi /etc/sysconfig/network-scripts/ifcfg-ens33 BOOTPROTOstatic ONBOOTyes …

openGauss学习笔记-122 openGauss 数据库管理-设置密态等值查询-密态支持函数/存储过程

文章目录 openGauss学习笔记-122 openGauss 数据库管理-设置密态等值查询-密态支持函数/存储过程122.1 创建并执行涉及加密列的函数/存储过程 openGauss学习笔记-122 openGauss 数据库管理-设置密态等值查询-密态支持函数/存储过程 密态支持函数/存储过程当前版本只支持sql和P…