文章目录
- 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地址