第六个小收获
众所周知,window系统有剪切文件夹或者复制文件夹,那么在qt内如何实现呢,之前有过类似的需求,所以记录一下
直接上代码:
首先创建一个拷贝复制剪切文件的线程:
线程.h文件,复制文件肯定是会放到线程中去处理的,这里使用了继承QThread
#ifndef COPYFILETHREAD_H
#define COPYFILETHREAD_H
#include <QThread>
// 拷贝/剪切文件的线程
class CopyFileThread : public QThread
{
Q_OBJECT
public:
/**
* @brief CopyFileThread 构造函数
* @param strSrcPath 源文件路径
* @param strDestPath 目标路径
* @param bIsCut false否 true是 默认为否
*/
CopyFileThread(const QString strSrcPath, const QString strDestPath,
bool bIsCut = false);
// dowork运行线程
void run() override;
private:
enum emRunStatus
{
COPY_FILE_FAILED = 3001, // 复制文件失败
DELETE_FILE_FAILED, // 删除文件失败
DESTFILEPATH_IS_SUB, // 目标文件夹是源文件夹的子文件夹
};
/**
* @brief CopyDir 复制文件夹内的所有文件
* @param strSourceDir 源文件夹
* @param strDestinationDir 目标文件夹
* @return true成功 false失败
*/
bool CopyDir(const QString strSourceDir, QString strDestinationDir);
/**
* @brief DeleteDir 删除文件夹内的所有文件
* @param strPath 文件夹路径
* @return true成功 false失败
*/
bool DeleteDir(const QString &strDirPath);
/**
* @brief FileNameEqualAddSuffix 文件名重复则添加文件后缀
* @param strSamePath 文件路径的引用 输出不重复的文件名
* @return true 成功 false失败
*/
bool FileNameEqualAddSuffix(QString &strSamePath);
signals:
/**
* @brief SignalSendProgress 发送进度信号
* @param iPercent 进度值
*/
void SignalProgress(const int iPercent);
/**
* @brief SignalSendMessage 文本信号传输
* @param strMessage 告知工作状态内容
*/
void SignalRunMessage(const QString strMessage);
/**
* @brief SignalRunFailed 发送运行失败信号
* @param uRunStatus 3001复制失败 3002删除失败
*/
void SignalRunFailed(const emRunStatus uRunStatus);
private:
/** 源路径(旧路径) */
QString m_strSourcePath;
/** 目标路径(新路径) */
QString m_strDestinatePath;
/** 是否是剪切文件夹 */
bool m_bIsCut;
};
#endif // COPYFILETHREAD_H
所有函数和信号都如上所示
线程.cpp文件
#include "CopyFileThread.h"
#include <QDir>
#include <QFile>
#include <QDebug>
/**
* @brief CopyFileThread 构造函数
* @param strSrcPath 源文件路径
* @param strDestPath 目标路径
* @param bIsCut false否 true是 默认为否
*/
CopyFileThread::CopyFileThread(const QString strSrcPath, const QString strDestPath,
bool bIsCut):
m_strSourcePath(strSrcPath),
m_strDestinatePath(strDestPath),
m_bIsCut(bIsCut)
{
}
void CopyFileThread::run()
{
// 路径不同 但是路径在当前源目录内
if(m_strSourcePath != m_strDestinatePath)
{
int iSrcSize = m_strSourcePath.size();
QString strTempDest = m_strDestinatePath.left(iSrcSize);
qDebug()<<strTempDest;
if(strTempDest == m_strSourcePath)
{
qDebug()<<u8"目标文件夹是源文件夹的子文件夹!";
emit SignalRunFailed(DESTFILEPATH_IS_SUB);
return;
}
}
// 复制文件
bool bRetCopyDir = CopyDir(m_strSourcePath,m_strDestinatePath);
if(!bRetCopyDir)
{
qDebug()<< __FUNCTION__ <<"copy file fail!";
// 发送失败位置
emit SignalRunFailed(COPY_FILE_FAILED);
return;
}
if(m_bIsCut)
{
// 若是剪切则调用删除文件函数
bool bRetDeleteDir = DeleteDir(m_strSourcePath);
if(!bRetDeleteDir)
{
qDebug() << __FUNCTION__ << "delete file fail!";
// 发送失败位置
emit SignalRunFailed(DELETE_FILE_FAILED);
return;
}
}
return;
}
/**
* @brief CopyDir 复制文件夹内的所有文件
* @param strSourceDir 源文件夹
* @param strDestinationDir 目标文件夹
* @return true成功 false失败
*/
bool CopyFileThread::CopyDir(const QString strSourceDir, QString strDestinationDir)
{
bool bRNT = true;
QDir sourceDir(strSourceDir);
QDir destDir(strDestinationDir);
// 若目标文件夹不存在 则创建
if(!destDir.exists())
{
destDir.mkdir(strDestinationDir);
}
else
{
// 存在则添加目标文件名后缀
FileNameEqualAddSuffix(strDestinationDir);
destDir.mkdir(strDestinationDir);
}
// 获取文件路径
QFileInfoList list = sourceDir.entryInfoList();
foreach(auto info,list)
{
if(info.fileName() == "." || info.fileName() == "..")
{
continue;
}
if(info.isDir())
{
//创建文件夹,调用递归
//要添加这句if判断 不然只要复制的话 会无限递归
if(strDestinationDir != info.filePath())
{
bRNT = CopyDir(info.filePath(),strDestinationDir + "/" + info.fileName());
}
continue;
}
//文件拷贝
QFile file(info.filePath());
bRNT = file.copy(strDestinationDir + "/" + info.fileName());
}
return bRNT;
}
/**
* @brief DeleteDir 删除文件夹内的所有文件
* @param strPath 文件夹路径
* @return
*/
bool CopyFileThread::DeleteDir(const QString &strDirPath)
{
bool bRNT = true;
// 容错处理 是否传入了空的路径||路径是否存在
if(strDirPath.isEmpty() || !QDir().exists(strDirPath))
{
bRNT = false;
return bRNT;
}
// 获取文件属性
QFileInfo FileInfo(strDirPath);
//如果是文件
if(FileInfo.isFile())
{
// 删除文件
QFile::remove(strDirPath);
}
else if(FileInfo.isDir()) //如果是文件夹
{
QDir qDir(strDirPath);
// 删除文件夹
qDir.removeRecursively();
}
return bRNT;
}
/**
* @brief FileNameEqualAddSuffix 文件名重复则添加文件后缀
* @param strSamePath 文件路径的引用 输出不重复的文件名
* @return true 成功 false失败
*/
bool CopyFileThread::FileNameEqualAddSuffix(QString &strSamePath)
{
bool bRTN = true;
int iNum = 1;
// 若有中文乱码 记得处理下
strSamePath += u8" - 副本";
QString tempStrPath = strSamePath;
QDir destDir(strSamePath);
// 若存在则一直改变iNum的值
while(destDir.exists())
{
++iNum;
strSamePath = tempStrPath + " (" + QString::number(iNum) + ")";
destDir.setPath(strSamePath);
}
return bRTN;
}
最后运行示例
#include "CopyFileThread.h"
// 假设要将"D:/NewData/data3"拷贝到D:下
// 路径根据需求处理
QString strSource("D:/NewData/data3");
// 若此时想拷贝到D盘 且选择了D盘
QString strDest("D:");
// 则要对目标文件夹做处理
QStringList strList = strSource.split("/");
strDest += "/" + strList.last();
// ↑这样拼接一下就是D:/data3了↑ 实际情况实际处理
// 第一个参数为目标文件夹 第二个参数为新的文件夹
CopyFileThread *pCopyFileThread = new CopyFileThread(strSource, strDest);
// 启动线程
pCopyFileThread->start();
// 线程释放
connect(pCopyFileThread,&CopyFileThread::finished,pCopyFileThread,&CopyFileThread::deleteLater);
connect(pCopyFileThread,&CopyFileThread::finished,this,[=]{
qDebug()<<u8"线程运行完毕,内存已释放";
});
运行测试文件内容:
测试文件内有三个文件data1.txt、data2.txt和文件夹data3,data3文件夹内有一个文件data3.txt
运行结果
可以看见复制成功,如果是剪切,则可以在实例化线程的构造函数内将第三个参数改为true,切换为剪切即可,这样源文件在复制完之后会删除。文件名处理也需要自己完善,上述只是示例