文章目录
- 1. 项目文件操作工具类设计
 
1. 项目文件操作工具类设计
根据前面的分析,这个文件类的基本属性如下:
- 文件大小信息
 - 文件最后修改时间
 - 文件最后一次访问时间,方便文件的热点管理
 - 文件名称,需要从http 请求行上的uri中获取
 - 基础文件读写接口 写数据为SetContent,读数据GetContent
 - 获取文件指定位置,指定长度的数据,使其支持断点续传
 - 获取文件夹的所有文件名称
 - 判断文件是否存在方法
 - 创建目录方法,名称是获取的文件名称
 - 文件压缩解压缩方法
 
错误日志函数log.hpp
// 项目错误日志打印
#pragma once
#include <iostream>
#include <stdio.h>
#include <string>
#include <time.h>
#define INFO 1
#define WARNING 2
#define ERROR 3
#define FATAL 4
#define LOG(level, message) Log(#level, message, __FILE__, __LINE__) // #将宏参数转化为字符串
// 时间戳转化为时间信息
static std::string convertTimeStamp2TimeStr(time_t timeStamp)
{
    struct tm *timeinfo = nullptr;
    char buffer[80];
    timeinfo = localtime(&timeStamp);
    strftime(buffer, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
    // printf("%s\n", buffer);
    return std::string(buffer);
}
// 日志级别+日志信息+时间戳+错误文件名称+错误行数
// 日志级别 INFO,WARNING,ERROR,FATAL
void Log(std::string level, std::string msg, std::string file_name, int line)
{
    std::cout << "[" << level << "]"
              << "[" << convertTimeStamp2TimeStr(time(nullptr)) << "]"
              << "[" << msg << "]"
              << "[" << file_name << "]"
              << "[" << line << "]" << std::endl;
}
 
文件工具类目录操作方法补充:
c库函数scandir函数:这个函数比较复杂使用这个也可以,这里使用C++17Filesystem类中的方法
 
 Filesystem library (since C++17)

 
 注意使用这个库需要在编译时加上-lstdc++fs
项目文件操作工具类设计:
#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sys/stat.h>
#include "log.hpp"
#include "../bundle/bundle.h"
// #include <filesystem>
#include <experimental/filesystem>
namespace CloudBackups
{
    namespace fs = std::experimental::filesystem;
    class FileUtil
    {
    private:
        std::string _filepath; // 文件名称 uri格式
        struct stat st;        // 文件属性
    public:
        FileUtil(const std::string &filepath)
        {
            _filepath = filepath;
            if (stat(_filepath.c_str(), &st) < 0)
            {
                LOG(WARNING, "get file stat failed! maybe this file not exits");
            }
        }
        int64_t filesize() { return st.st_size; }         // 获取文件大小,失败返回-1
        time_t last_modify_time() { return st.st_mtime; } // 获取文件最后修改时间
        time_t last_visit_time() { return st.st_atime; }  // 获取文件最后访问时间
        std::string filename()                            // 文件名称
        {
            size_t pos = _filepath.find_last_of("/");
            if (pos == std::string::npos)
            {
                return _filepath;
            }
            return _filepath.substr(pos + 1);
        }
        bool getPoslen(std::string &body, size_t pos, size_t len) // 从文件中读取len个字节,从pos位置开始读取,读取内容放到body中,为了实现断点续传
        {
            size_t size = this->filesize(); // 文件大小
            if (pos >= size)
            {
                LOG(ERROR, "pos is out of range!");
                return false;
            }
            if (pos + len > size)
            {
                LOG(ERROR, "pos + len is out of range!");
                return false;
            }
            std::ifstream ifs;
            ifs.open(_filepath.c_str(), std::ios::binary);
            if (!ifs.is_open())
            {
                LOG(ERROR, "open file failed!");
                return false;
                
            }
            ifs.seekg(pos, std::ios::beg);
            body.resize(len);
            ifs.read(&body[0], len);
            if (!ifs.good())
            {
                // 上次读取出错
                LOG(ERROR, "read file failed!");
                ifs.close();
                return false;
            }
            ifs.close();
            return true;
        }
        bool getContent(std::string &body) // 获取整体的文件数据
        {
            size_t size = this->filesize();
            return getPoslen(body, 0, size);
        }
        bool setContent(const std::string &body) // 设置文件内容
        {
            std::ofstream ofs;
            ofs.open(_filepath.c_str(), std::ios::binary);
            if (!ofs.is_open())
            {
                LOG(ERROR, "open file failed!");
                return false;
            }
            ofs.write(body.c_str(), body.size());
            if (!ofs.good())
            {
                // 上次写入出错
                LOG(ERROR, "write file failed!");
                ofs.close();
                return false;
            }
            ofs.close();
            return true;
        }
        bool zip(const std::string &packname) // 文件压缩功能,传入压缩后名称
        {
            // 读取源文件所有内容
            std::string body;
            if (this->getContent(body) == false)
            {
                // 获取源文件数据失败
                LOG(ERROR, "get file content failed!");
                return false;
            }
            // 对数据进行压缩
            std::string packed = bundle::pack(bundle::LZIP, body);
            // 保存压缩后的数据
            FileUtil file(packname);
            if (file.setContent(packed) == false)
            { // 保存压缩后的数据失败
                LOG(ERROR, "save zip file content failed!");
                return false;
            }
            return true;
        }
        bool unzip(const std::string &filename) // 文件解压缩功能,传入解压缩文件名称
        {
            // 读取当前压缩的数据
            std::string body;
            if (this->getContent(body) == false)
            {
                // 获取源文件数据失败
                LOG(ERROR, "get zip file content failed!");
                return false;
            }
            // 对压缩的数据进行解压
            std::string unpacked = bundle::unpack(body);
            // 保存解压数据
            FileUtil file(filename);
            if (file.setContent(unpacked) == false)
            { // 保存解压数据失败
                LOG(ERROR, "save unzip file content failed!");
                return false;
            }
            return true;
        }
        bool isExit() { return fs::exists(_filepath); } // 判断文件是否存在
        bool mkdir()                                    // 创建文件夹
        {
            if (this->isExit())
            {
                return true;
            }
            return fs::create_directories(_filepath);
        }
        bool ls(std::vector<std::string> &files) // 扫描文件夹,并返回里面的文件
        {
            for (auto &pos : fs::directory_iterator(_filepath))
            {
                if (fs::is_directory(pos) == true)
                {
                    continue; // 目录不出来
                }
                files.push_back(fs::path(pos).relative_path().string()); // 获取文件的相对路径
            }
            return true;
        }
    };
}
 

 
根据上图可知,项目文件属性获取,文件读写,文件压缩与解压缩基本功能没有问题
代码位置:
 Gitee地址
 Gitee地址



















