Skip to content

fix: update current filename display during p7zip compression#396

Open
LiHua000 wants to merge 1 commit intolinuxdeepin:release/eaglefrom
LiHua000:release/eagle
Open

fix: update current filename display during p7zip compression#396
LiHua000 wants to merge 1 commit intolinuxdeepin:release/eaglefrom
LiHua000:release/eagle

Conversation

@LiHua000
Copy link
Copy Markdown
Contributor

  • Calculate current file based on progress percentage and file size
  • Fix issue where p7zip only displays the last filename during compression
  • Add weighted calculation by file size for accurate display timing
  • Separate compression and extraction logic to preserve extraction functionality

log: fix bug

Bug: https://pms.uniontech.com/bug-view-357565.html

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @LiHua000, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: LiHua000

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

- Calculate current file based on progress percentage and file size
- Fix issue where p7zip only displays the last filename during compression
- Add weighted calculation by file size for accurate display timing
- Separate compression and extraction logic to preserve extraction functionality

log: fix bug

Bug: https://pms.uniontech.com/bug-view-357565.html
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

这段代码主要针对压缩/解压工具的进度显示和文件名解析逻辑进行了优化。我将从语法逻辑、代码质量、代码性能和代码安全四个方面进行审查,并提出改进意见。

1. 语法逻辑

问题点:

  1. 成员变量初始化时机m_totalFileSizeaddFiles 函数中计算。如果 m_files 在其他地方(如 deleteFilescopyFiles)被修改或使用,而在那些操作前没有调用 addFiles,则 m_totalFileSize 可能为 0 或过期数据,导致压缩进度计算错误。
  2. 边界条件处理:在计算 fileIndex 时,虽然有边界检查,但逻辑稍显冗余。例如在循环中 fileIndex = i; // 防止最后一个文件时索引越界 这行代码放在循环末尾,实际上如果循环正常结束(未 break),fileIndex 会是最后一个元素的索引,这是正确的,但注释和位置容易让人困惑。
  3. 文件名获取逻辑重复:在 WT_Add 分支中,无论总大小是否为 0,获取文件名的逻辑(strfilename = ... if (strfilename.isEmpty()) ...)是完全重复的。

改进建议:

  1. 统一初始化:建议在所有涉及文件列表变更的操作(如添加、删除)开始时,都更新 m_totalFileSize,或者提供一个 updateTotalFileSize() 私有函数供调用。
  2. 简化循环逻辑:可以使用 std::accumulate 或更清晰的循环结构来计算当前文件索引。
  3. 提取重复代码:将获取文件名的逻辑提取为一个 lambda 函数或私有辅助函数。

2. 代码质量

问题点:

  1. 代码可读性handleProgress 函数变得非常长且嵌套层级深,特别是 WT_Add 分支。这降低了代码的可维护性。
  2. 魔法数字:代码中存在 count + 2 这样的硬编码偏移量,缺乏解释,容易出错。
  3. 注释:虽然添加了注释,但部分注释(如 // p7zip在压缩时只显示最后一个文件名)解释了“是什么”,但最好能解释“为什么”以及依赖的 CLI 输出格式。

改进建议:

  1. 函数拆分:建议将 handleProgress 中针对不同 m_workStatus 的处理逻辑拆分为独立的私有函数,例如 handleExtractProgresshandleAddProgress 等。
  2. 常量定义:将 count + 2 等偏移量定义为常量,并说明其含义(例如 CLI 输出前缀的长度)。
  3. 代码格式line.contains("\b\b\b\b") == true 中的 == true 是多余的,直接写 line.contains("\b\b\b\b") 即可。

3. 代码性能

优点:

  1. 缓存计算结果:引入 m_totalFileSize 并在 addFiles 时预先计算,避免了在频繁调用的 handleProgress(进度更新通常很频繁)中遍历 m_files 列表求和,这是一个很好的性能优化。

潜在问题与建议:

  1. 字符串操作:在 handleProgress 中,line.containsline.indexOf 被多次调用。由于 lineconst QString&,这本身开销不大,但在高频调用下仍有优化空间。建议减少不必要的字符串扫描,或者利用 QStringRef 进行子字符串操作(代码中已部分使用)。
  2. 循环查找文件:在 WT_Add 分支中,每次进度更新都需要遍历 m_files 来找到当前文件。如果文件数量非常大(例如数千个),这会带来性能损耗。
    • 优化建议:可以考虑预先计算一个“累计大小”数组(QVector<qint64>),存储每个文件结束时的累计大小。这样在 handleProgress 中可以使用 std::upper_bound 进行二分查找,将复杂度从 O(N) 降低到 O(log N)。

4. 代码安全

问题点:

  1. 整数溢出m_totalFileSizeqint64,但在计算 compressedSize = (percentage * m_totalFileSize) / 100 时,如果 m_totalFileSize 接近 qint64 最大值,乘法可能导致溢出。
  2. 空指针/数组越界风险:虽然代码中添加了 if (!m_files.isEmpty())fileIndex 的边界检查,这是好的做法。但在 strfilename = QFileInfo(m_files[fileIndex].strFullPath).fileName(); 这行,如果 strFullPath 为空或格式异常,QFileInfo 的行为需要确认是否符合预期(通常会返回空字符串,相对安全)。
  3. 数据一致性m_totalFileSize 是一个成员变量,但在多线程环境下(如果 handleProgress 是通过信号槽跨线程调用的),需要确保 m_filesm_totalFileSize 的读写是线程安全的。目前看代码似乎是单线程处理或通过信号队列串行化,但需确认。

改进建议:

  1. 防止溢出:在进行乘法运算前,可以先进行除法,或者使用更大的整数类型(如果可用),或者检查是否会溢出。例如:compressedSize = (static_cast<double>(percentage) / 100.0) * m_totalFileSize;(注意浮点精度)。
  2. 防御性编程:在访问 m_files 元素前,确保索引绝对安全。虽然现有检查已覆盖大部分情况,但可以更严谨。

综合改进代码示例

针对上述分析,以下是重构后的代码片段建议,重点展示了逻辑优化和性能改进:

// 在 cliinterface.h 中添加辅助成员
// QVector<qint64> m_accumulatedFileSizes; // 累计文件大小,用于二分查找

// 在 addFiles 中初始化
// m_totalFileSize = 0;
// m_accumulatedFileSizes.clear();
// for (const auto &file : m_files) {
//     m_totalFileSize += file.qSize;
//     m_accumulatedFileSizes.append(m_totalFileSize);
// }

// 在 handleProgress 中的 WT_Add 处理逻辑优化
void CliInterface::handleAddProgress(int percentage) {
    if (m_files.isEmpty()) return;

    QString strfilename;
    int fileIndex = 0;

    // 辅助 lambda:获取显示用的文件名
    auto getDisplayName = [](const FileEntry& entry) {
        return entry.strFileName.isEmpty() ? 
               QFileInfo(entry.strFullPath).fileName() : 
               entry.strFileName;
    };

    if (m_totalFileSize == 0) {
        // 文件数量平均分配
        fileIndex = (percentage * (m_files.size() - 1)) / 100;
    } else {
        // 使用二分查找根据大小定位文件
        // 注意:这里需要防止 qint64 溢出,使用 double 进行中间计算
        double compressedSize = (static_cast<double>(percentage) / 100.0) * m_totalFileSize;
        
        // 使用 std::upper_bound 查找第一个大于 compressedSize 的累计大小位置
        auto it = std::upper_bound(m_accumulatedFileSizes.begin(), 
                                   m_accumulatedFileSizes.end(), 
                                   static_cast<qint64>(compressedSize));
        fileIndex = std::distance(m_accumulatedFileSizes.begin(), it);
        
        // 边界修正:如果计算出的索引超出范围,取最后一个
        if (fileIndex >= m_files.size()) {
            fileIndex = m_files.size() - 1;
        }
    }

    strfilename = getDisplayName(m_files[fileIndex]);
    if (!strfilename.isEmpty()) {
        emit signalCurFileName(strfilename);
    }
}

// 在 handleProgress 主函数中调用
void CliInterface::handleProgress(const QString &line) {
    // ... 前面的代码 ...
    
    if (percentage > 0) {
        if (line.contains("\b\b\b\b")) {
            if (m_workStatus == WT_Extract) {
                // ... 解压逻辑 ...
            } else if (m_workStatus == WT_Add) {
                handleAddProgress(percentage); // 调用拆分后的函数
            } else {
                // ... 删除/重命名逻辑 ...
            }
            
            emit signalprogress(percentage);
        }
    }
    // ...
}

总结

这段代码的改进初衷是好的(缓存总大小以优化性能),但在实现细节上还有提升空间。主要建议包括:

  1. 逻辑解耦:将庞大的 handleProgress 拆分为更小的函数。
  2. 性能优化:对于大量文件,使用预处理数组和二分查找替代线性查找。
  3. 健壮性:注意整数运算的溢出风险,并确保文件索引的绝对安全。
  4. 可维护性:消除重复代码,使用常量代替魔法数字,提升注释质量。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants