【云备份】文件操作实用工具类设计

news2025/2/23 3:35:13

文章目录

  • 为什么要单独设计文件工具类?
  • 整体实现
    • Filesize ——文件大小
      • stat接口
    • LastMTime ——最后一次修改时间
    • LastATime —— 最后一次访问时间
    • FileName —— 文件名称
    • GetPostLen ——获取文件指定位置 指定长度的数据
    • GetContnet —— 读取文件数据
    • SetContent ——向文件中写入数据
    • Compress —— 压缩
    • UnCompress —— 解压缩
    • firesystem手册使用
    • Exists—— 判断文件是否存在
    • CreateDirectory ——创建目录
    • ScanDirectory ——返回指定文件夹中所有的文件路径名称
  • 整体代码
    • util.hpp
    • makefile
    • cloud.cpp (测试代码)

为什么要单独设计文件工具类?

由于在客户端和服务器端中 都涉及到文件的读写
所以要先设计 封装文件操作类,当该类设计好后 对文件的操作时就会变的简单化


功能:
1. Filesize 获取文件的大小
2. LastModTime 获取文件最后一次修改时间
3. LastAccessTime 获取文件最后一次访问时间
4. FileName 获取文件路径名中的文件名称
5. SetContent 向文件中写入数据
6. GetContnet 读取文件数据
7. GetPostLen 获取文件指定位置 指定长度的数据
8. GetDirectory 返回指定文件夹中所有的文件路径名称
9. Exists 判断文件是否存在,若不存在则创建
10. CreateDirectory 创建目录
11. Compress 文件压缩
12. Uncompress 文件解压缩


整体实现

创建一个 util.hpp
在其内部 创建一个 cloud 命名空间
在cloud中,创建一个FileUtil类
在私有权限中,设置一个 _filename 整体文件名称(可能包含文件路径)


Filesize ——文件大小

stat接口

stat 通过文件的路径名称访问文件,获取文件的状态属性信息,再放入到buf中
若返回小于0,则表示访问失败


stat结构体中包含的属性最主要的有
st_size(文件大小)
st_atime(文件最后一次访问时间)
st_mtime(文件最后一次修改时间)


若访问文件失败,则打印 get file size failed
若访问成功,则返回 stat类型结构体 的 st_size 即可 表示 文件大小


LastMTime ——最后一次修改时间

同样使用stat函数,若返回值小于0则说明访问失败 返回 get fire size faied
若访问成功,则 返回 stat结构体的 st_mtime 即可 表示 文件最后一次修改时间


LastATime —— 最后一次访问时间

使用stat函数,若返回值小于0则说明访问失败 返回 get fire size faied
若访问成功,则 返回 stat结构体的 st_atime 即可 表示 文件最后一次访问时间


FileName —— 文件名称

路径之间都是以 / 来进行间隔的
所以只需找到最后一个 / ,从该/ 开始的下一个位置开始 就是文件名的起始位置

string 中的 find_last_of()函数可以用来查找某个字符最后一次出现的位置


若没有找到 / ,则表示 filename 就为 文件名称

若找到/ ,则从 /的下一个位置开始截断 直到 文件末尾 , 将子串整体作为文件名称返回


GetPostLen ——获取文件指定位置 指定长度的数据

获取文件是要从文件中读取数据 所以使用 ifstream 类型
ios::binary 表示 二进制
所以 以二进制的形式打开 _filename 文件
若打开文件失败,则打印 open file failed


若打开文件成功,还需判断下pos位置 是否超过 文件的整体大小
若超过文件整体大小,则 返回 false


使用 seekg 跳转到文件pos位置
调整body的大小为 文件大小len
将文件数据放入 body中
若读取出错,则返回false


GetContnet —— 读取文件数据

先通过FileSize 获取文件大小
再通过调用 GetPostLen 函数 即可读取到整个文件的数据


SetContent ——向文件中写入数据

写入文件数据 就为输入 所以使用 ofstream 类型
使用 二进制的方式打开文件 filename
打开失败,则返回false


将body数据写入到文件中
若写入失败,则返回false



Compress —— 压缩

将filename的文件内容 全部读取到 body中
若读取失败,则返回 false


选择 LZIP 压缩格式,body作为文件内容,使用 pack 进行压缩,返回值就是压缩之后的数据


通过packname实例化一个新对象 fu
再将 压缩的数据 packed 读取到文件中
若写入失败,则返回false
若写入成功,则返回true



UnCompress —— 解压缩

将filename的文件内容 全部读取到 body中
若读取失败,则返回 false


将body中的文件内容进行解压缩


通过filename实例化一个新对象 fu
再将 解压缩的数据 unpacked 读取到文件中
若写入失败,则返回false
若写入成功,则返回true



firesystem手册使用

在C++17中 支持的一个文件系统 filesystem 完成目录的遍历操作

点击查看:firesystem手册地址


打开文档后 向下翻

找到 create_directory 创建目录(单层级)
create_directories 创建目录(多层级)


只需传入目录的路径名即可


exists 文件是否存在


将文件名传入即可


遍历目录的迭代器 directory_iterator

Exists—— 判断文件是否存在

fs作为文件系统的命名空间


调用 filesystem手册中的 exists 接口 传入文件名 即可达到 判断文件是否存在的作用


CreateDirectory ——创建目录

如果不存在就创建,如果存在就不需要创建了
调用 filesystem手册中的 create_directories 接口 传入目录的路径名 即可达到 创建目录的作用


ScanDirectory ——返回指定文件夹中所有的文件路径名称

需要先判断,在遍历的过程中,是否为文件,若不为文件,则不进行操作


借助firesystem手册中的 is_directory 作用为 判断是否是一个目录


将文件名传入即可


迭代器的返回数据 不是一个 string 类型
所以当要添加文件时 不能直接向arry中添加 p


借助firesystem手册中的 path 类 进行实例化 一个path对象


想要返回文件的相对路径 ,所以借助path类中的 relative_path

最终为 获取带有路径的文件名 中的 string 对象


整体代码

util.hpp

#include<iostream>
#include<fstream>
#include<string>
#include<vector>
#include<sys/stat.h>
#include"bundle.h"
#include<experimental/filesystem>

namespace cloud
{
  namespace fs=std::experimental::filesystem;

 class FileUtil
 {
  private:
          std::string _filename;//文件名称
  public:
          FileUtil(const std::string &filename):_filename(filename)//构造函数 
          {}
 
          int64_t FileSize()//文件大小
          {
            struct stat st;
           if( stat(_filename.c_str(),&st)<0)
           {
              std::cout<<"get file size failed!\n";	
              return -1;
           }
           return st.st_size;           
          }

          time_t  LastMTime()//文件最后一次修改时间
          {
           struct stat st;
           if( stat(_filename.c_str(),&st)<0)
           {
              std::cout<<"get file size failed!\n";
              return -1;
           }  
           return st.st_mtime; 
          }
           
          time_t  LastATime()//文件最后一次访问时间
          {
           struct stat st;
           if( stat(_filename.c_str(),&st)<0)
           {
              std::cout<<"get file size failed!\n";
              return -1;
           }
           return st.st_atime;
          }

          std::string FileName()//文件名称
          {
            // ./abc/test.txt
            size_t pos=_filename.find_last_of("/");
            if(pos==std::string::npos)
            {
             return _filename;
            }
            return _filename.substr(pos+1);
          }
         bool GetPostLen(std:: string *body,size_t pos,size_t len)//获取文件数据
          {
             std::ifstream ifs;
             ifs.open(_filename,std::ios::binary);//以二进制方式打开文件
             if(ifs.is_open()==false)
             {
               std::cout<<"read file failed"<<std::endl;
               return false;
             }
             //打开成功,获取文件数据
             size_t fsize=this->FileSize();//获取文件大小
             if(pos+len>fsize)//若pos开始位置超过了文件大小
             {
               std::cout<<"get file len is error"<<std::endl;
               return false;
             }
             ifs.seekg(pos,std::ios::beg);//从文件起始位置偏移到pos位置处
             body->resize(len);
              ifs.read(&(*body)[0], len);//读取文件所有数据到 body中
 
             if(ifs.good()==false)//读取出错
             {
               std::cout<< "get file content fialed "<<std::endl;
               ifs.close();
               return false;
             }
             ifs.close();

              return true;
          }

          bool GetContent(std::string *body) //获取整体文件数据
          {
              size_t fsize=this->FileSize();//获取文件大小
              return GetPostLen(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"<<std::endl;
              return false;
            }
            ofs.write(&body[0], body.size());//将body数据写入到文件中
            if(ofs.good()==false)//写入失败
            {
               std::cout<<"write file content failed"<<std::endl;
               ofs.close();  
               return false;
            }
            
             ofs.close();
             return true;
          }

          bool compress(const std::string &packname) //压缩
          {
             //读取文件数据
              std::string body;
              if(this->GetContent(&body)==false)
              {
                std::cout<<"compress get file content failed"<<std::endl;
                return false;
              } 
             //对数据进行压缩
             std::string packed=bundle::pack(bundle::LZIP,body);
             

             //将压缩数据存储到压缩包文件中
              FileUtil fu(packname);
              if(fu.Setcontent(packed)==false)//写入数据失败
              {
                std::cout<<"compress write packed data failed"<<std::endl;
                return false;
              }
            return true;
          }

          bool UnCompress(const std::string &filename)//解压缩
          {
              //将当前压缩包数据读取出来
              std::string body;
               if(this->GetContent(&body)==false)//获取文件内容
              {
                std::cout<<"compress get file content failed"<<std::endl;
                return false;
              } 
                            
              //对压缩的数据进行解压缩
              std::string unpacked=bundle::unpack(body);

              //将解压缩的数据写入到新文件中
               FileUtil fu(filename);
              if(fu.Setcontent(unpacked)==false)//写入数据失败
              {
                std::cout<<"uncompress write packed data failed"<<std::endl;
                return false;
              }
              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)//浏览目录
          {
             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;
          }
  };
}

 

makefile

cloud:cloud.cpp  util.hpp bundle.cpp
	g++ $^ -o $@ -lpthread  -lstdc++fs
.PHONY:clean
clean:
	rm -f cloud

cloud.cpp (测试代码)

  #include"util.hpp"
  

  void 	FileUtilTest(const std::string &filename)
  {
    /*
    1.
    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;
     2.
     // 将 filename 文件内容 全部读取到 body中
     cloud::FileUtil fu(filename);
     std::string body;
     fu.GetContent(&body);//读取文件数据
     
     //再将body中的数据内容 读取到文件中
      cloud::FileUtil nfu("./hello.txt");
      nfu.Setcontent(body); //将body写入文件中
      return;
     
     3.
     //将packname数据进行压缩 再将其进行解压 放入 hello.txt中
     std::string packname=filename +".lz";
     cloud::FileUtil fu(filename);
     fu.compress( packname);//将压缩的数据放入packname中
     cloud::FileUtil pfu( packname);
     pfu.UnCompress("./hello.txt");//将packname中的数据放入 hello.txt中
     return;
     */

     cloud::FileUtil fu(filename);
     fu.CreateDirectory();//创建目录
     std::vector<std::string>arry;
     fu.ScanDirectory(&arry);//浏览目录
     for(auto &a: arry)
     {
      std::cout<<a<<std::endl;
     }
     return;
}  
 
  
  int main(int argc,char*argv[])
  {
    FileUtilTest(argv[1]); 
    return 0;
  }

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

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

相关文章

文献速递:人工智能在新生儿重症监护室:现在是时候了

人工智能在新生儿重症监护室&#xff1a;现在是时候了 01 文献速递介绍 文章介绍了AI的多学科特性&#xff0c;包括计算机科学、数学、神经科学和哲学。AI的目标是通过各种计算和算法技术创建智能机器。尽管早期对人类水平AI的预测未能实现&#xff0c;但对AI的期待仍然强烈…

图书馆管理系统源码(Java)

Book包->内含Book类与BookList类 Book类 用于初始化图书并对其进行操作 BookList类 用于存放多本图书 Book类 package Book;public class Book {private String name;private String author;private int price;private String type;private boolean isBorrow;//写一个…

10.打印楼梯图案和笑脸【2023.11.25】

1.问题描述 打印楼梯图案和笑脸 2.解决思路 3.代码实现 #include<stdio.h> int main(){printf("11\n");for(int i0;i<10;i){for(int j0;j<i;j){printf("FF"); }printf("\n");} return 0; }4.运行结果

Java研学-异常

一 异常 异于正常状态的显示,即控制台显示结果与预期的不一致 // 抛出异常java.lang.ArrayIndexOutOfBoundsException int[] nums new int[2]; System.out.print(nums[2]);二 异常分类 1 检测性异常:有称为非运行时异常,一般是在编写代码的过程中编程软件直接报错 2 非检测…

用Python写的自动答题脚本,正确率99%,刷课必备

咱们上学的时候&#xff0c;有些课程&#xff0c;不是很重要所以没去看&#xff0c;但是又要刷题&#xff0c;这时候&#xff0c;自动答题脚本就很关键&#xff0c;全程全自动&#xff0c;正确率还嘎嘎高&#xff01; 所以咱们今天来用Python写一个自动答题脚本&#xff0c;正…

图的建立基本操作

#include <stdio.h> #include <stdlib.h> #include <stdbool.h> // 添加头文件#define MAX_VERTEX_NUM 100 //图中最大顶点数//struct ArcNode* nextarc; //ArcNode* firstarc; //这两个是很有必要的&#xff0c;如果你没有这两个指针&#xff0c;你就无法判…

2.前端--HTML标签1【2023.11.25】

1.基本语法规范 HTML 标签是由尖括号包围的关键词&#xff0c;例如 <html>。HTML 标签通常是成对出现的&#xff0c;例如 和 &#xff0c;我们称为双标签。有些特殊的标签必须是单个标签&#xff08;极少情况&#xff09;&#xff0c;例如 <br />我们称为单标签。 …

2022年12月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 默认小猫角色和气球角色都是显示状态,小猫程序如下图所示,气球没有程序,点击绿旗,舞台上最终显示的效果是?( ) A:可能出现6个不同位置的小猫和6个小球 B:可能出现6个不同位…

Python基于jieba+wordcloud实现文本分词、词频统计、条形图绘制及不同主题的词云图绘制

目录 序言&#xff1a;第三方库及所需材料函数模块介绍分词词频统计条形图绘制词云绘制主函数 效果预览全部代码 序言&#xff1a;第三方库及所需材料 编程语言&#xff1a;Python3.9。 编程环境&#xff1a;Anaconda3&#xff0c;Spyder5。 使用到的主要第三方库&#xff1a;…

P12 C++静态关键字static

目录 01 前言 02 静态变量static 03 extern关键字 04 静态函数 最后的话 01 前言 static 关键字在 C 中有两个意思&#xff0c;这个取决于上下文。 第一种情况是在类或结构体外部使用 static 关键字&#xff0c;另一种是在类或者结构体内部使用 static。 类外面的 static…

vscode运行c++程序如何支持c++11

参考https://zhuanlan.zhihu.com/p/269244754 更改setting.json文件

[环境配置]vscode免密ssh的设置流程

测试环境&#xff1a; windows 11 ubuntu16.04 vmware 第一步&#xff1a;生成密钥 cmd打开输入&#xff1a;ssh-keygen -t rsa 一路回车后可以在C:\Users\用户名\.ssh路径看到id_rsa.pub&#xff0c;我们打开这个文件&#xff0c;用记事本打开即可&#xff0c;然后复制里…

二十一、数组(6)

本章概要 数组排序Arrays.sort的使用并行排序binarySearch二分查找parallelPrefix并行前缀 数组排序 根据对象的实际类型执行比较排序。一种方法是为不同的类型编写对应的排序方法&#xff0c;但是这样的代码不能复用。 编程设计的一个主要目标是“将易变的元素与稳定的元素…

王者荣耀——Java

代码如下&#xff1a; sxt Background package sxt;import java.awt.*; //背景类 public class Background extends GameObject{public Background(GameFrame gameFrame) {super(gameFrame);}Image bg Toolkit.getDefaultToolkit().getImage("C:\\Users\\24465\\Desk…

Hibernate 脏检查和刷新缓存机制

刷新缓存: Session是Hibernate向应用程序提供的操作数据库的主要接口,它提供了基本的保存,更新,删除和加载java对象的方法,Session具有一个缓存,可以管理和追踪所有持久化对象,对象和数据库中的相关记录对应,在某些时间点,Session会根据缓存中对象的变化来执行相关SQL语句,将对…

【负载均衡】这些内容你需要知道下

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

【刷题宝典NO.4】

目录 公交站间的距离 生命游戏 公交站间的距离 https://leetcode.cn/problems/distance-between-bus-stops/ 环形公交路线上有 n 个站&#xff0c;按次序从 0 到 n - 1 进行编号。我们已知每一对相邻公交站之间的距离&#xff0c;distance[i] 表示编号为 i 的车站和编号为 …

Kotlin学习——流程控制,when,循环,range工具 kt里的equals if实现类似三元表达式的效果

Kotlin 是一门现代但已成熟的编程语言&#xff0c;旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作&#xff0c;并提供了多种方式在多个平台间复用代码&#xff0c;以实现高效编程。 https://play.kotlinlang.org/byExample/01_introduction/02_Functio…

KVM虚拟机的NAT网络模式原理及过程展示

NAT的方式及原理 NAT方式是KVM安装后的默认方式。 它支持主机与虚拟机的互访&#xff0c;同时也支持虚拟机访问互联网&#xff0c;但不支持外界访问虚拟机。 default是宿主机安装虚拟机支持模块的时候自动安装的。 其中 virbr0是由宿主机虚拟机支持模块安装时产生的虚拟网络接…

Python编程技巧 – Lambda函数

Python编程技巧 – Lambda函数 Python Programming Skills – Lambda Functions By JacksonML 2023-11-25 在前文介绍过Python函数&#xff0c;一个函数用def关键字声明&#xff0c;不带或带有参数&#xff0c;并以冒号结束&#xff1b;函数块根据结果由解释器确定返回值动态…