之前写了一篇《批处理替换指定目录下所有文件夹名和文件名》,但是会存在些小问题,为了优雅的解决问题,打算用Qt开发个应用软件处理一下,同时把存在的问题都解决了。当然前提是目标机允许运行Qt打包的程序。
实现原理很简单,用QFileDialog让用户选择指定目录,通过深度优先搜索(DFS)逐层逐个遍历文件夹和文件,如果名称符合替换条件则替换相应的字符串,需要注意的是搜索时先搜索子文件夹内部再判断文件夹本身。
为了更方便使用,支持用户输入多个字符串,任意一个匹配成功即认为满足替换条件。例如在下图所示的软件界面中的指定文本,支持输入“aa$bb$cc”,如果文件名中带有aa或bb或cc,均视为满足替换条件,会自动替换为目标文本。
软件界面:
RenameFilesName.h
#ifndef RENAMEFILESNAME_H
#define RENAMEFILESNAME_H
#include <QFileDialog>
#include <QWidget>
#include <QDebug>
#if defined(_MSC_VER)
#pragma execution_character_set("utf-8")
#endif
namespace Ui {
class RenameFilesName;
}
class RenameFilesName : public QWidget
{
Q_OBJECT
public:
explicit RenameFilesName(QWidget *parent = 0);
~RenameFilesName();
protected:
void dfsRequireFiles(QString path); // dfs文件列表
bool dealIsContainsText(QString name, QString &newName); // 判断是否包含文本
private slots:
void on_pushButtonPicDir_clicked(); // 选取目录
void on_pushButtonSearch_clicked(); // 开始查询
private:
Ui::RenameFilesName *ui;
int m_numSuccess; // 替换成功的数量
int m_numFailed; // 替换失败的数量
int m_totFile; // 总文件数量
int m_totDir; // 总文件夹数量
};
#endif // RENAMEFILESNAME_H
RenameFilesName.cpp
#include "RenameFilesName.h"
#include "ui_RenameFilesName.h"
RenameFilesName::RenameFilesName(QWidget *parent) :
QWidget(parent),
ui(new Ui::RenameFilesName)
{
ui->setupUi(this);
}
RenameFilesName::~RenameFilesName()
{
delete ui;
}
void RenameFilesName::dfsRequireFiles(QString path)
{
QDir dir(path);
QFileInfoList file_list = dir.entryInfoList(QDir::Files | QDir::Hidden | QDir::NoSymLinks); // 获取文件列表
QFileInfoList folder_list = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); // 获取文件夹里列表
for (int i = 0; i < file_list.size(); i++)
{
++m_totFile;
QString newName;
if (dealIsContainsText(file_list.at(i).fileName(), newName))
{
QString originPath = file_list.at(i).absoluteFilePath();
QString newPath = file_list.at(i).absolutePath() + "/" + newName;
QDir dir(originPath);
if (dir.rename(originPath, newPath))
{
ui->listWidget->addItem(newPath);
++m_numSuccess;
}
else
++m_numFailed;
}
}
for (int i = 0; i != folder_list.size(); i++)
{
QString name = folder_list.at(i).absoluteFilePath();
++m_totDir;
dfsRequireFiles(name); // 递归子目录
QString newName;
if (dealIsContainsText(folder_list.at(i).fileName(), newName))
{
QString originPath = folder_list.at(i).absoluteFilePath();
QString newPath = folder_list.at(i).absolutePath() + "/" + newName;
QDir dir(originPath);
if (dir.rename(originPath, newPath))
{
ui->listWidget->addItem(newPath);
++m_numSuccess;
}
else
++m_numFailed;
}
}
}
bool RenameFilesName::dealIsContainsText(QString name, QString &newName)
{
QStringList listTargetStr = ui->lineEditText->text().split("$");
for (int i = 0; i < listTargetStr.size(); ++i)
{
if (name.contains(listTargetStr.at(i)))
{
newName = name.replace(listTargetStr.at(i), ui->lineEditTargetText->text());
return true;
}
}
return false;
}
void RenameFilesName::on_pushButtonPicDir_clicked()
{
QString dirName = QFileDialog::getExistingDirectory(this, tr("打开目录"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
ui->lineEditDir->setText(dirName);
}
void RenameFilesName::on_pushButtonSearch_clicked()
{
ui->labelStatus->setText("查询开始!");
QString dirName = ui->lineEditDir->text();
ui->listWidget->clear();
m_numSuccess = 0;
m_numFailed = 0;
m_totDir = 0;
m_totFile = 0;
dfsRequireFiles(dirName);
ui->labelStatus->setText(QString("查询结束!共查询 %1 个子文件夹,%2 个子文件。其中,替换成功的有 %3 条,替换失败的有 %4 条。").arg(m_totDir).arg(m_totFile).arg(m_numSuccess).arg(m_numFailed));
}
实测效果:
在指定目录DisplayImage里,将所有文件名中数字前的前缀统一命名为Image。
分析一下文件名,前缀中不符合规范的命名有image、IMAGE、IME、IMG四种,所以在软件的指定文本中输入image$IMAGE$IME$IMG,目标文本输入Image,点击“开始替换”即可。
修改后效果: