项目实现:云备份②(文件操作、Json等工具类的实现)

云备份

  • 前言
  • 文件操作实用工具类设计
    • 文件属性的获取
    • 文件的读写操作
    • 文件压缩与解压缩的实现
    • 文件目录操作
  • Json 实用工具类设计
  • 编译优化

前言

如果有老铁不知道当前项目实现的功能是什么的话,可以先移步这篇文章内容: 云备份项目的介绍

其中介绍了云备份项目的基本功能、环境搭建的详情。

文件操作实用工具类设计

文件属性的获取

创建 src 目录,在 src 目录下进行 util.hpp 文件的代码编写,实现文件工具类:

  1. int64_t FileSize()获取文件大小
  2. time_t LastMTime()获取文件最后一次的修改时间
  3. time_t LastATime()获取文件最后一次的访问时间
  4. std::string FileName()获取文件名称
#include <iostream>
#include <string>
#include <vector>
#include <sys/stat.h>namespace cloud
{class FileUtil{public:FileUtil(const std::string &filename): _filename(filename){}// 获取文件大小int64_t FileSize(){struct stat st; // 用于获取文件属性if (stat(_filename.c_str(), &st) < 0){std::cout << "get filesize false\n";return -1;}return st.st_size;}// 获取文件最后一次的修改时间time_t LastMTime(){struct stat st; // 用于获取文件属性if (stat(_filename.c_str(), &st) < 0){std::cout << "get file last modify time false\n";return -1;}return st.st_mtime; // 文件的修改时间}// 获取文件最后一次的访问时间time_t LastATime(){struct stat st; // 用于获取文件属性if (stat(_filename.c_str(), &st) < 0){std::cout << "get file last access time false\n";return -1;}return st.st_atime; // 文件的修改时间}// 获取文件名std::string FileName(){//找到切分文件名称的最后一个/auto pos = _filename.find_last_of("/"); if(pos == std::string::npos){//当前文件没有路径return _filename;}//找到/后,进行字符串切割return _filename.substr(pos+1);}private:std::string _filename;};}

代码测试:

#include "util.hpp"void FileUtilText(const std::string &filename)
{   cloud::FileUtil fu(filename);std::cout << fu.FileSize() << std::endl;std::cout << fu.LastMTime() << std::endl;std::cout << fu.LastATime() << std::endl;std::cout << fu.FileName() << std::endl;
}int main(int argc, char* argv[])
{FileUtilText(argv[1]);return 0;
}

结果如下:
在这里插入图片描述
注意:这里直接访问到的是文件修改时间、访问时间,其实是时间戳。

文件的读写操作

继续在 util.hpp 文件内完善 FileUtil 类:

  1. bool GetPosLen(std::string *body, size_t pos, size_t len)获取指定位置到指定长度的文件数据
  2. bool GetContent(std::string *body)获取整个文件的数据内容
  3. bool SetContent(const std::string &body)向文件写入数据

下面所有代码是在类中实现的,为了方便演示,只展示当前标题要实现的代码:

#include <iostream>
#include <string>
#include <vector>
#include <sys/stat.h>
#include <fstream>namespace cloud
{class FileUtil{public:  //其他函数...// 获取指定位置到指定长度的文件数据bool GetPosLen(std::string *body, size_t pos, size_t len){size_t fsize = FileSize(); // 获取文件总长度// 判断文件总长度是否符合 pos+len 长度if (pos + len > fsize){std::cout << "get file len is error\n";return false;}std::ifstream ifs;ifs.open(_filename.c_str(), std::fstream::binary); // 以二进制的方式打开文件if (ifs.is_open() == false){std::cout << "read open file false\n";return false;}// 定位文件到pos位置ifs.seekg(pos, std::ios::beg);body->resize(len); // 扩容字符串// 读取数据ifs.read(&(*body)[0], len);if (ifs.good() == false){// 读取出错std::cout << "get file content false\n";ifs.close();return false;}ifs.close();return true;}// 获取整个文件的数据内容bool GetContent(std::string *body){size_t fsize = FileSize();return GetPosLen(body, 0, fsize);}// 向文件写入数据bool SetContent(const std::string &body){std::ofstream ofs;ofs.open(_filename.c_str(), std::ios::binary); //打开目标文件if(ofs.good() == false){//打开文件失败std::cout << "write open file false\n";return false;}//将原文件内容写入到目标文件中ofs.write(&body[0], body.size());if(ofs.good() == false){//写入失败std::cout << "write file file false\n";ofs.close();return false;}//写入成功ofs.close();return true;}private:std::string _filename;};
}

测试代码:

void FileUtilText(const std::string &filename)
{   cloud::FileUtil fu(filename);std::string body;fu.GetContent(&body);//获取文件内容到body字符串中cloud::FileUtil ufu("./test.txt"); //在当前目录的一个./text.txt文件ufu.SetContent(body); //将body字符串内容写入到./text.txt文件中
}int main(int argc, char* argv[])
{FileUtilText(argv[1]);return 0;
}

测试结果如下:
在这里插入图片描述

在这里拿 Makefile 文件举例:

将 Makefile 文件内容进行读取,放入到 text.txt文件中。对比两个文件生成哈希值可以看到一模一样,读取文件内容到写入文件过程是没有问题的。

文件压缩与解压缩的实现

依旧是完善 FileUtil 类,实现两个接口:

  1. bool Compress(const std::string &packname)压缩文件
  2. bool UnCompress(const std::string &filename)解压文件

当然,在这里需要引入第三方库 bundle 进行文件的解压缩操作,不知道如何搭环境的小伙伴可以看这篇文章:项目环境搭建

bundle 库下载后,在 src 目录下,引入 bundle.h、bundle.cpp 文件即可:
在这里插入图片描述
实现文件的解压缩功能,在 util.hpp 文件内的 FileUtil 类进行编写:

#include <iostream>
#include <string>
#include <vector>
#include <sys/stat.h>
#include <fstream>
#include "bundle.h"namespace cloud
{class FileUtil{public:  //其他函数...//压缩文件bool Compress(const std::string &packname){std::string body;//获取文件内容if(GetContent(&body) == false){std::cout << "compress get file content falsed!\n";return false;}//对刚刚提取的数据进行压缩,使用LZIP压缩格式std::string packed = bundle::pack(bundle::LZIP, body);//将压缩数据存储到压缩文件中if(SetContent(packname) == false){std::cout << "compress write packed data falsed!\n";return false;}return true;}//解压文件bool UnCompress(const std::string &filename){std::string body;//提取压缩包文件数据if(GetContent(&body) == false){std::cout << "uncompress get file content falsed!\n";return false;}//解压数据std::string unpacked = bundle::unpack(body);//将解压数据放入到文件中if(SetContent(unpacked ) == false){std::cout << "uncompress write packed data falsed!\n";return false;}return true;}private:std::string _filename;};
}

引入了 bundle.cpp 文件后,在 Makefile 文件中也要有对应内容修改:

cloud:cloud.cc util.hpp bundle.cppg++ -o $@ $^ -std=c++11 -lpthread.PHONY:clean
clean:rm -f cloud

编写测试代码:

#include "util.hpp"void FileUtilText(const std::string &filename)
{std::string packname = filename + ".lz"; //.lz压缩包后缀cloud::FileUtil fu(filename);// 压缩文件fu.Compress(packname);cloud::FileUtil pfu(packname);// 解压后的文件内容放入到 test.txtpfu.UnCompress("./test.txt");
}int main(int argc, char *argv[])
{FileUtilText(argv[1]);return 0;
}

文件目录操作

继续完善 FileUtil 类,实现三个接口:

  1. bool Exists()判断文件是否存在
  2. bool CreateDirectory()创建目录
  3. bool ScanDirectory(std::vector<std::string> *arry)获取目录下的文件信息

代码实现:

#include <iostream>
#include <string>
#include <vector>
#include <sys/stat.h>
#include <fstream>
#include <experimental/filesystem>
#include "bundle.h"namespace cloud
{// 引用std::experimental::filesystem命名空间namespace fs = std::experimental::filesystem;class FileUtil{public:  //其他函数...// 判断文件是否存在bool Exists(){return fs::exists(_filename);}// 创建文件目录bool CreateDirectory(){// 文件存在,无需创建目录if (Exists()) return true;// 否则创建这个目录return fs::create_directories(_filename);}// 遍历整个目录,查看文件信息bool ScanDirectory(std::vector<std::string> *arry){// 迭代遍历目录下的文件for (auto &p:fs::directory_iterator(_filename)){if (fs::is_directory(p) == true) continue;// 如果是一个目录,不再往下遍历// 将带有路径的文件名称push到arr数组中arry->push_back(fs::path(p).relative_path().string());}return true;}private:std::string _filename;};
}

在这里是直接调用了 C++17 的 filesystem 函数,对此在Makefile 中,要连接对应的库:-lstdc++fs

cloud:cloud.cc util.hpp bundle.cppg++ -o $@ $^ -lpthread -std=c++11 -lstdc++fs.PHONY:clean
clean:rm -f cloud

测试代码:

#include "util.hpp"void FileUtilText(const std::string &filename)
{cloud::FileUtil fu(filename);fu.CreateDirectory(); //创建文件目录std::vector<std::string> array;fu.ScanDirectory(&array); //遍历目录文件,存储到array数组中// 遍历目录文件for (auto &e : array)std::cout << e << std::endl;
}int main(int argc, char *argv[])
{FileUtilText(argv[1]);return 0;
}

测试结果如下:
在这里插入图片描述
先前是没有 test 目录的,运行程序后,直接创建 test 目录。

接下来在 test 目录下创建一些文件、目录,再次运行 cloud ,查看结果:
在这里插入图片描述
可以看到在 test 目录下是文件的都遍历了一遍,abc 目录没有进行遍历。

至此,FileUtil 类主要功能就实现完了。接下来是 JsonUtil 类的实现:

Json 实用工具类设计

JsonUtil 类实现依旧是在 util.hpp 文件中进行编写。其类中主要实现两个接口:

  1. static bool Serialize(const Json::Value &root, std::string *str)序列化
  2. static bool UnSerialize(const std::string &str, Json::Value *root)反序列化

使用前需要下载 Json 第三方库,具体的下载方式可以参考这篇文章:Json下载与使用

代码实现:

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <jsoncpp/json/json.h>class JsonUtil
{
public://序列化static bool Serialize(const Json::Value &root, std::string *str){Json::StreamWriterBuilder swb;std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());std::stringstream ss;if(sw->write(root, &ss) != 0){std::cout << "json write failed\n";return false;}//将序列化后的字符串保存到str中*str = ss.str(); return true;}//反序列化static bool UnSerialize(const std::string &str, Json::Value *val){Json::CharReaderBuilder crb;std::unique_ptr<Json::CharReader> cr(crb.newCharReader());std::string err;//将反序列化内容存储到str中bool ret = cr->parse(str.c_str(), str.c_str()+str.size(), val, &err); if(ret == false){std::cout << "parse error:" << err << std::endl;return false;}return true;}
};

为了编译时不报错,需要对 Makefile 文件进行修改,加入 -ljsoncpp选项:

cloud:cloud.cc util.hpp bundle.cppg++ -o $@ $^ -lpthread -lstdc++fs -std=c++14 -ljsoncpp

测试代码:

void JsonUtilTest()
{const char *name = "张三";int age = 18;float score[] = {90.5, 77, 100};Json::Value root;root["姓名"] = name;root["年龄"] = age;root["成绩"].append(score[0]);root["成绩"].append(score[1]);root["成绩"].append(score[2]);std::string json_str;cloud::JsonUtil::Serialize(root, &json_str); //序列化操作std::cout << json_str << std::endl;Json::Value val;cloud::JsonUtil::UnSerialize(json_str, &val);//反序列化操作std::cout << val["姓名"].asString() << std::endl; std::cout << val["年龄"].asInt() << std::endl; for(auto &e : val["成绩"]){std::cout << e << std::endl; }
}int main(int argc, char *argv[])
{JsonUtilTest();return 0;
}

测试结果如下:
在这里插入图片描述

编译优化

云备份项目引入了 bundle 第三方压缩库,整个 bundle.cpp 内容还是比较大的。

为了代码编写的正确性,我们每写完一段代码后都要进行测试。每次测试都要进行整体代码的编译,包括 bundle库。

由于 bundle.cpp 编译时长比较久,难免会很难受。对此,下面对 bundle.cpp 直接生成静态库,编译时直接链接就可以了。这样就可以很好的避免编译等待时间过久的问题。

关于动静态库的制作,可以参考小编的这篇文章:动静态库的介绍

下面开始进行操作:

  1. 使用 g++ 编译器,将 bundle.cpp 源文件生成 .o文件
g++ -c bundle.cpp -o bundle.o -std=c++11
  1. 制作 bundle 静态库
 ar -cr libbundle.a bundle.o

在这里插入图片描述
只要看到 libbundle.a 文件,就说明制作成功了。对于 src 目录下的 bundle.cpp、bundle.o,可以直接删除。

  1. 创建 lib 目录,将 libbundle.a 剪切到 lib 目录下即可

在这里插入图片描述
4. 更改 Makefile 内容,编译所用到的库

cloud:cloud.cc util.hppg++ -o $@ $^ -lpthread -lstdc++fs -std=c++14 -ljsoncpp -L./lib -lbundle.PHONY:clean
clean:rm -f cloud

此后,我们对整个项目进行编译,无需再对 bundle.cpp 进行处理,可以节省很多时间。

后续内容会持续更新,喜欢的老铁可以点赞、收藏加关注,感谢大家的观看!

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

在 Dify 中高效利用 SiliconCloud API

引言 SiliconCloud 以其丰富的模型库和卓越的处理速度&#xff0c;在 Dify 平台上实现高效工作流和智能代理变得轻而易举。本文将指导您如何在 Dify 中集成 SiliconCloud 的强大功能。 集成 SiliconCloud 模型 步骤一&#xff1a;设置 SiliconCloud 账户 首先&#xff0c;您…

5. Python之数据类型

Python数据类型有数值型&#xff0c;字符串型&#xff0c;布尔型等等 内置函数type()&#xff0c;可以查看变量的数据类型 。 一、数值类型 整数&#xff08;没有小数部分&#xff0c;包含正整数&#xff0c;负整数&#xff0c;0&#xff0c;默认为十进制数&#xff09;&…

PHP:强大的Web开发语言

PHP&#xff1a;强大的Web开发语言 一、PHP 简介及优势 PHP 的基本概念 PHP&#xff08;PHP: Hypertext Preprocessor&#xff09;即 “超文本预处理器”&#xff0c;是一种通用开源脚本语言&#xff0c;最初由 Rasmus Lerdorf 于 1994 年创建。它可以在服务器上执行&#xf…

正则表达式匹配整数与浮点数失败与解决方案

正则表达式匹配整数与浮点数失败与解决方案 问题描述问题分析解决方案总结 问题描述 在处理数据的时候需要提取文本内整数与浮点数&#xff0c;这个时候想到使用正则表达式&#xff0c;咨询百度文心一言给出以下方案及参考代码 import re text "我有100元&#xff0c;…

华为地图服务功能概览 -- HarmonyOS自学7

华为地图服务式Harmony OS生态下的一个地图服务&#xff0c;为开发者提供强大而便捷的地图能力&#xff0c;助力全球开发者实现个性化地图呈现&#xff0c;地图搜索和路线规划功能。 主要包括七大功能&#xff1a;静态图&#xff0c;场景化控件&#xff0c;地点搜索&#xff0c…

函数的认识(二)

函数的基础知识可查看&#xff1a;函数的认识&#xff08;一&#xff09; &#xff08;1&#xff09;函数说明文档 函数是纯代码语言&#xff0c;想要理解其含义&#xff0c;就需要一行行的去阅读理解代码&#xff0c;效率比较低。 我们可以给函数添加说明文档&#xff0c;辅…

Python 解析 Charles JSON Session File (.chlsj)

Charles 代理&#xff0c;是一款抓包软件&#xff0c;可以帮助我们抓取浏览器请求跟响应。 1、在 Filter 里面输入需要抓包的网址 2、右键 Export Session 3、文件类型选择 JSON Session File (.chlsj) 保存 4、解析响应的数据结构 response.body.text 是文本字符串。 # 导入…

Navicat使用 笔记04

Navicat调用数据库 1.创建一个自己的链接&#xff08;文件-->新建连接-->MySQL&#xff09; 进入到这个界面中&#xff1a; 【注意&#xff1a;密码是下载登录软件时设定过的】 创建一个连接完成&#xff08;通过双击激活&#xff09;。 2.在创建好的连接中创建数据库…

Linux-mysql5.7-mysql8.0安装包下载及安装教程,二合一

一、安装包下载 1、手动下载 MySQL :: Download MySQL Community Server 2、wegt下载 wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.24-linux-glibc2.12-x86_64.tar.gz 登录自己的liunx &#xff0c;复制上面的命令下载。 二、手动安装 1、上传压缩包到…

蓝桥杯-基于STM32G432RBT6的LCD进阶(LCD界面切换以及高亮显示界面)

目录 一、页面切换内容详解 1.逻辑解释 2.代码详解 code.c&#xff08;内含详细讲解&#xff09; code.h main.c 3.效果图片展示 ​编辑 二、页面选项高亮内容详解 1.逻辑解释 2.读入数据 FIRST.第一种高亮类型 code.c&#xff08;内含代码详解&#xff09; code.…

kubernetes中pause容器的作用与源码详解

概述 摘要&#xff1a;上一篇文章我们介绍了kubernetes是如何通过pause容器来构建一个pod。本文我们对pause容器做一个总结&#xff0c;并再此基础上次深入浅出&#xff0c;从pause容器的源码详细了解pause容器的实现原理。 正文 pause容器是什么 在 Kubernetes 中&#xff…

超高速传输 -- Fixed Grid与Flexible Grid

Fixed Grid 传统的40波/80波DWDM系统采用Fixed Grid固定光谱方式&#xff0c;波长间隔固定为100GHz或者50GHz&#xff0c;中心频率也是固定的。在Fixed Grid方式下&#xff0c;带宽无法灵活调配。 随着系统中信号速率的提升&#xff0c;光信号的频谱也在变宽&#xff1b;当多速…

SpringSecurity原理解析(八):CSRF防御解析

一、CsrfFilter CsrfFilter 主要功能是用来防止csrf攻击 一、什么是CSRF攻击 跨站请求伪造&#xff08;英语&#xff1a;Cross-site request forgery&#xff09;&#xff0c;也被称为 one-click attack 或者 session riding&#xff0c;通常缩写为 CSRF 或者 XSRF&#xff0c…

有关C# .NET Core 过滤器的使用

想用一个过滤器实现特定接口的审核日志记录&#xff0c;结果报了错&#xff0c;看了看感觉有些基础要补&#xff0c;所以想记录下来 错误&#xff1a; 在属性过滤器中使用了依赖注入&#xff0c;结果在应用在控制层接口时报了传参的错 //过滤器 public class AuditRecordFil…

数据时代,职场离不开的远程控制工具

中秋了大概率是在正常放假了吧&#xff0c;如果突发遇到需要你处理的文件怎么办呢&#xff1f;其实有远程操作工具你就不用到办公室了。向日葵远程控制软件这些工具就可以帮我们远程实现控制电脑操作。如果你也有这方面需求就继续看吧&#xff0c;这次我将介绍几款我用过效果比…

(c++)字符串相加(真没想到字符串还有相加运算)

#include<iostream> #include<string> using namespace std;int main() {string ch1 "你好";string ch2 "再见";string ch3 ch1 ch2;cout << ch3 << endl;system("pause");return 0; } 运行结果&#xff1a; 学了c…

SpringBoot Kafka发送消息与接收消息实例

前言 Kafka的基本工作原理 我们将消息的发布&#xff08;publish&#xff09;称作 producer(生产者)&#xff0c;将消息的订阅&#xff08;subscribe&#xff09;表述为 consumer&#xff08;消费者&#xff09;&#xff0c;将中间的存储阵列称作 broker(代理)&#xff0c;这…

Qt --- 信号和信号槽

前言 Linux信号Signal&#xff0c;系统内部的通知机制&#xff0c;进程间通信方式。 信号源&#xff1a;谁发的信号。 信号的类型&#xff1a;哪种类别的信号。 信号的处理方式&#xff1a;注册信号处理函数&#xff0c;在信号被触发的时候自动调用执行。 Qt中的信号和Lin…

利士策分享,中秋佳节:月满人团圆的文化传承与演绎

利士策分享&#xff0c;中秋佳节&#xff1a;月满人团圆的文化传承与演绎 在中国丰富多彩的传统节日中&#xff0c;中秋节以其独特的魅力&#xff0c;承载着深厚的文化底蕴和民族情感。 这一节日的起源&#xff0c;宛如一幅缓缓展开的历史画卷&#xff0c;融合了古人对天象的…

栈、队列、树、哈希表

栈 先进后出&#xff0c;添加元素直接memcpy 到对应数组位置就可以&#xff0c;top是栈中存储的元素个数&#xff0c;最后一个元素下标为top-1&#xff1b; 删除元素时直接top--&#xff1b; 后面添加进入的数据会覆盖原来在栈上被删除的数据。 main.c符号匹配 链栈 main.c 队…