项目背景
能够管理本地和远程文件(例如通过网络共享路径)并执行常见操作的工具。这些操作包括文件复制、剪切、删除等,且操作后能动态更新用户界面中显示的文件系统。项目中需要使用 QTreeView
作为文件浏览的界面,通过多线程处理文件操作任务,并从配置文件中读取管理路径。
项目功能概述
- 文件及文件夹管理:通过
QTreeView
显示目录结构,递归遍历文件夹,并能进行操作后自动刷新。 - 多线程文件操作:为每个文件操作(复制、剪切、删除)创建了专门的线程,避免主线程阻塞。
- 配置文件读取:支持从
config.ini
中读取配置文件来获取需要管理的文件路径,支持网络共享路径和本地路径。 - 操作反馈:在执行文件操作时,使用信号-槽机制向用户界面反馈操作进度。
- 灵活性:通过添加根目录的机制,保持目标路径结构与源路径一致。
关键功能说明
1. 配置文件读取
项目需要从配置文件 config.ini
读取路径信息。以下是 config.ini
文件的示例结构:
[operpath]
1\val="E:\\Qice Images"
2\val="//DESKTOP-IU21M5R//Qice Images"
我们通过 QSettings
读取配置文件中的每个路径,并返回管理路径的列表。
关键代码:
#include <QSettings>
#include <QStringList>QStringList getOperPaths(const QString &configFilePath = "config.ini") {QSettings settings(configFilePath, QSettings::IniFormat);settings.beginGroup("operpath");QStringList operPaths;QStringList groups = settings.childGroups();foreach (const QString &group, groups) {settings.beginGroup(group);QString path = settings.value("val").toString();operPaths << path;settings.endGroup();}settings.endGroup();return operPaths;
}
2. 递归加载文件目录到 QTreeView
为了展示文件系统结构,项目中递归遍历给定的文件路径,并将其加载到 QTreeView
中。该函数每次都会递归进入子目录,加载所有文件夹和文件。
关键代码:
void MainWindow::populateFileList(const QStringList &initialDirPaths) {model->clear(); // 清除现有数据foreach (QString path, initialDirPaths) {QDir dir(path);if (!dir.exists()) {continue;}QStandardItem *rootItem = new QStandardItem(dir.dirName());rootItem->setData(path, Qt::UserRole);model->invisibleRootItem()->appendRow(rootItem);findFilesInDirectories(path, rootItem); // 递归加载文件}ui->treeView->expandAll(); // 展开所有节点
}void MainWindow::findFilesInDirectories(const QString &dirPath, QStandardItem *parentItem) {QDir dir(dirPath);QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);foreach (QFileInfo fileInfo, list) {QStandardItem *item = new QStandardItem(fileInfo.fileName());item->setData(fileInfo.absoluteFilePath(), Qt::UserRole);parentItem->appendRow(item);if (fileInfo.isDir()) {findFilesInDirectories(fileInfo.absoluteFilePath(), item); // 递归进入子目录}}
}
3. 多线程文件操作(复制、剪切、删除)
文件操作任务(如复制、剪切、删除)是耗时的,因此使用了 QThread
来处理这些操作。每个操作完成后会触发信号,通知主线程进行刷新。
关键代码:
void ImageMoverThread::run() {if (rootPath.isEmpty()) {emit progress(0, tc("源路径为空"));return;}QDir dir(rootPath);if (!dir.exists()) {emit progress(0, tc("源路径不存在"));return;}if (m_operationType == Copy || m_operationType == Cut) {if (targetPath.isEmpty()) {emit progress(0, tc("目标路径为空"));return;}QString rootFolderName = QDir(rootPath).dirName();QString targetRootPath = targetPath + "/" + rootFolderName;if (!QDir(targetRootPath).exists()) {if (!QDir().mkdir(targetRootPath)) {emit progress(0, tc("无法创建目标根目录文件夹"));return;}}processDirectory(rootPath, targetRootPath); // 递归处理复制/剪切if (m_operationType == Cut) {deleteDirectory(rootPath); // 剪切操作后删除源文件}} else if (m_operationType == Delete) {deleteDirectory(rootPath); // 删除操作}emit operationCompleted(); // 操作完成,发出信号刷新视图
}
4. 删除操作
删除操作会递归删除文件夹中的文件,但保留文件夹本身。
关键代码:
void ImageMoverThread::deleteDirectory(const QString &dirPath) {QDir dir(dirPath);QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);foreach (QFileInfo fileInfo, list) {if (fileInfo.isDir()) {deleteDirectory(fileInfo.absoluteFilePath()); // 递归处理子文件夹} else {if (!QFile::remove(fileInfo.absoluteFilePath())) {emit progress(0, tc("删除文件失败: ") + fileInfo.fileName());}}}emit progress(100, tc("目录已清理文件: ") + dirPath);
}
5. 刷新 QTreeView
当文件操作完成后,触发刷新文件树结构的操作,以便显示最新的文件状态。
关键代码:
void MainWindow::refreshTreeView() {QStringList paths = getOperPaths(); // 重新获取管理路径populateFileList(paths); // 重新填充文件树
}