文件压缩处理(一)

文件压缩使用的bit7z库

将大写转换为小写

cpp 复制代码
static std::string toLower(std::string_view str) noexcept {
    std::string result;
    result.reserve(str.size());
    std::ranges::transform(str, std::back_inserter(result), [](unsigned char word) { return std::tolower(word); });
    return result;
}

文件系统结构体

采用树状结构,节点信息包含路径以及文件名,用递归的方式将文件挂载在对应的父节点下

cpp 复制代码
struct FileItem {
    FileItem* parent = nullptr;
    std::string filePath;
    std::string fileName;
    quint64 fileSize = 0;
    quint64 modityTime = 0;
    quint32 index = 0;
    std::string extension;
    std::vector<FileItem*> childs;
    bool isDir = false;
    FileItem() = default;
    FileItem(FileItem* p_parent, std::string_view path, std::string_view name, quint64 size, quint64 time,
             uint32_t u_index, std::string_view extension_str, const std::vector<FileItem*>& list, bool is_dir) noexcept
        : parent(p_parent),
          filePath(path),
          fileName(name),
          fileSize(size),
          modityTime(time),
          index(u_index),
          extension(extension_str),
          childs(list),
          isDir(is_dir) {}
    ~FileItem() {
        for (FileItem* child : childs) {
            delete child;
        }
        childs.clear();
    }

    FileItem(FileItem&& other) noexcept
        : parent(other.parent),
          filePath(std::move(other.filePath)),
          fileName(std::move(other.fileName)),
          fileSize(other.fileSize),
          modityTime(other.modityTime),
          index(other.index),
          extension(std::move(other.extension)),
          childs(std::move(other.childs)),
          isDir(other.isDir) {
        for (auto* child : childs) {
            if (child) {
                child->parent = this;
            }
        }
        other.childs.clear();
    }
    FileItem& operator=(FileItem&& other) noexcept {
        if (this != &other) {
            for (FileItem* child : childs) {
                del(child);
            }
            childs.clear();

            parent = other.parent;
            filePath = std::move(other.filePath);
            fileName = std::move(other.fileName);
            fileSize = other.fileSize;
            modityTime = other.modityTime;
            index = other.index;
            extension = std::move(other.extension);
            childs = std::move(other.childs);
            isDir = other.isDir;
            for (auto* child : childs) {
                if (child) {
                    child->parent = this;
                }
            }
            other.childs.clear();
        }
        return *this;
    }
    FileItem(const FileItem&) = delete;
    FileItem& operator=(const FileItem&) = delete;

    void add(FileItem* pItem) noexcept {
        std::string_view const item_name = pItem->fileName;
        const std::string& item_path = pItem->filePath;
        std::string const parent_path = item_path.substr(0, item_path.rfind(item_name));

        if (parent_path.empty()) {
            pItem->parent = this;
            if (!find(item_name)) childs.push_back(pItem);
            return;
        }

        if (parent_path.length() >= filePath.length() && parent_path.starts_with(filePath)) {
            std::string child_path = parent_path.substr(filePath.size());

            if (!child_path.empty() && (child_path[0] == '\\' || child_path[0] == '/')) {
                child_path = child_path.substr(1);
            }

            if (child_path.empty()) {
                pItem->parent = this;
                childs.push_back(pItem);
                return;
            }

            size_t const pos = child_path.find_first_of("\\/");
            std::string const sub_dir = (pos != std::string::npos) ? child_path.substr(0, pos) : child_path;

            for (auto* itr : childs) {
                if (itr->fileName == sub_dir) {
                    itr->add(pItem);
                    return;
                }
            }

            auto* child = new FileItem(
                this, this->filePath + (this->filePath.empty() ? "" : "\\") + sub_dir, sub_dir, 0, 0, 0, "", {}, true

            );
            childs.push_back(child);
            child->add(pItem);
        }
    }
    void del(FileItem* pItem) {
        if (!pItem) return;

        auto itr = std::ranges::find(childs, pItem);
        if (itr != childs.end()) {
            delete pItem;
            childs.erase(itr);
        }
    }

    void sort(const std::function<bool(FileItem*, FileItem*)>& compare) noexcept {
        std::ranges::partition(childs, [](FileItem* item) { return item->isDir; });

        auto first_file_node = std::ranges::find_if_not(childs, [](FileItem* item) { return item->isDir; });

        std::ranges::sort(childs.begin(), first_file_node, compare);
        std::ranges::sort(first_file_node, childs.end(), compare);
    }

    void sortDefault() noexcept {
        sort([](FileItem* left, FileItem* right) {
            if (left->isDir && !right->isDir) return true;
            if (!left->isDir && right->isDir) return false;
            return true;
        });
    }
    void sortByName(bool bAsc = true) {
        sort([bAsc](FileItem* left, FileItem* right) {
            return bAsc ? toLower(left->fileName) > toLower(right->fileName)
                        : toLower(left->fileName) < toLower(right->fileName);
        });
    }
    void sortBySize(bool bAsc = true) {
        sort([bAsc](FileItem* left, FileItem* right) {
            return bAsc ? left->fileSize > right->fileSize : left->fileSize < right->fileSize;
        });
    }
    void sortByType(bool bAsc = true) {
        sort([bAsc](FileItem* left, FileItem* right) {
            return bAsc ? toLower(left->extension) > toLower(right->extension)
                        : toLower(left->extension) < toLower(right->extension);
        });
    }
    void sortByTime(bool bAsc = true) {
        sort([bAsc](FileItem* left, FileItem* right) {
            return bAsc ? left->modityTime > right->modityTime : left->modityTime < right->modityTime;
        });
    }
    FileItem* find(std::string_view path) noexcept {
        if (filePath == path) return this;
        for (auto* child : childs) {
            if (!child) continue;
            if (FileItem* item = child->find(path)) {
                return item;
            }
        }
        return nullptr;
    }
    FileItem* find(uint32_t u_index) noexcept {
        if (this->index == u_index && parent) return this;
        for (auto* child : childs) {
            if (!child) continue;
            if (FileItem* item = child->find(u_index)) {
                return item;
            }
        }
        return nullptr;
    }

    void printTree(int depth = 0) const {
        std::stringstream out;
        for (int i = 0; i < depth; ++i) {
            out << "\t";
        }

        // 打印当前节点信息
        out << filePath << "--" << index << "\n";

        spdlog::debug(out.str());

        // 递归打印子节点
        for (const auto* child : childs) {
            if (child) {
                child->printTree(depth + 1);
            }
        }
    }
};
相关推荐
yaoxin5211232 分钟前
397. Java 文件操作基础 - 创建常规文件与临时文件
java·开发语言·python
小短腿的代码世界6 分钟前
Qt日志系统深度解析:从qDebug到企业级日志框架
开发语言·qt
REDcker1 小时前
浏览器端Web程序性能分析与优化实战 DevTools指标与工程清单
开发语言·前端·javascript·vue·ecmascript·php·js
yngsqq1 小时前
平面图环 内轮廓
c#
我命由我123452 小时前
Kotlin 开发 - lateinit 关键字
android·java·开发语言·kotlin·android studio·android-studio·android runtime
Halo_tjn2 小时前
Java Set集合相关知识点
java·开发语言·算法
许彰午3 小时前
我手写了一个 Java 内存数据库(二):B+ 树的插入与分裂
java·开发语言·面试
大飞记Python3 小时前
【2026更新】Python基础学习指南(AI版)——04数据类型
开发语言·人工智能·python
rockey6273 小时前
AScript之eval函数详解
c#·.net·script·eval·expression·动态脚本
Alice-YUE4 小时前
【js高频八股】防抖与节流
开发语言·前端·javascript·笔记·学习·ecmascript