使用 Qt 复制目录

发布于 2024-08-26 12:41:42 字数 71 浏览 7 评论 0原文

我想将目录从一个驱动器复制到另一个驱动器。我选择的目录包含许多子目录和文件。

我如何使用 Qt 实现相同的功能?

I want to copy a directory from one drive to another drive. My selected directory contains many sub directories and files.

How can I implement the same using Qt?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

拔了角的鹿 2024-09-02 12:41:42
void copyPath(QString src, QString dst)
{
    QDir dir(src);
    if (! dir.exists())
        return;

    foreach (QString d, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
        QString dst_path = dst + QDir::separator() + d;
        dir.mkpath(dst_path);
        copyPath(src+ QDir::separator() + d, dst_path);
    }

    foreach (QString f, dir.entryList(QDir::Files)) {
        QFile::copy(src + QDir::separator() + f, dst + QDir::separator() + f);
    }
}
void copyPath(QString src, QString dst)
{
    QDir dir(src);
    if (! dir.exists())
        return;

    foreach (QString d, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
        QString dst_path = dst + QDir::separator() + d;
        dir.mkpath(dst_path);
        copyPath(src+ QDir::separator() + d, dst_path);
    }

    foreach (QString f, dir.entryList(QDir::Files)) {
        QFile::copy(src + QDir::separator() + f, dst + QDir::separator() + f);
    }
}
梦巷 2024-09-02 12:41:42

您可以手动执行以下操作:

1)。使用下面的 func 您可以生成文件夹/文件列表(递归地) - 目标文件。

static void recurseAddDir(QDir d, QStringList & list) {

    QStringList qsl = d.entryList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);

    foreach (QString file, qsl) {

        QFileInfo finfo(QString("%1/%2").arg(d.path()).arg(file));

        if (finfo.isSymLink())
            return;

        if (finfo.isDir()) {

            QString dirname = finfo.fileName();
            QDir sd(finfo.filePath());

            recurseAddDir(sd, list);

        } else
            list << QDir::toNativeSeparators(finfo.filePath());
    }
}

2)。然后您可以开始将文件从目标列表复制到新的源目录,如下所示:

for (int i = 0; i < gtdStringList.count(); i++) {

    progressDialog.setValue(i);
    progressDialog.setLabelText(tr("%1 Coping file number %2 of %3 ")
        .arg((conf->isConsole) ? tr("Making copy of the Alta-GTD\n") : "")
        .arg(i + 1)
        .arg(gtdStringList.count()));

    qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

    if (progressDialog.wasCanceled()) {

        // removing tmp files/folders
        rmDirectoryRecursive(tmpFolder);
        rmDirectoryRecursive(tmpFolderPlus);
        setEnableGUI(true);
        return;
    }

    // coping
    if (!QFile::copy(gtdStringList.at(i), tmpStringList.at(i))) {

        if (warningFlag) {

            QMessageBox box(this);
            QString name = tr("Question");
            QString file1 = getShortName(gtdStringList.at(i), QString("\\...\\"));
            QString file2 = getShortName(tmpStringList.at(i), QString("\\...\\"));
            QString text = tr("Cannot copy <b>%1</b> <p>to <b>%2</b>"   \
               "<p>This file will be ignored, just press <b>Yes</b> button" \
               "<p>Press <b>YesToAll</b> button to ignore other warnings automatically..."  \
               "<p>Or press <b>Abort</b> to cancel operation").arg(file1).arg(file2);

            box.setModal(true);
            box.setWindowTitle(name);
            box.setText(QString::fromLatin1("%1").arg(text));
            box.setIcon(QMessageBox::Question);
            box.setStandardButtons(QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::Abort);

            switch (box.exec()) {                   
                case (QMessageBox::YesToAll):
                    warningFlag = false;
                    break;
                case (QMessageBox::Yes):
                    break;
                case (QMessageBox::Abort):
                    rmDirectoryRecursive(tmpFolder);
                    rmDirectoryRecursive(tmpFolderPlus);
                    setEnableGUI(true);
                    return;
            }
        }
    }
}

仅此而已。祝你好运!

Manually, you can do the next things:

1). with func below you generate folders/files list (recursively) - the destination files.

static void recurseAddDir(QDir d, QStringList & list) {

    QStringList qsl = d.entryList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);

    foreach (QString file, qsl) {

        QFileInfo finfo(QString("%1/%2").arg(d.path()).arg(file));

        if (finfo.isSymLink())
            return;

        if (finfo.isDir()) {

            QString dirname = finfo.fileName();
            QDir sd(finfo.filePath());

            recurseAddDir(sd, list);

        } else
            list << QDir::toNativeSeparators(finfo.filePath());
    }
}

2). then you may to start copying files from destination list to the new source directory like that:

for (int i = 0; i < gtdStringList.count(); i++) {

    progressDialog.setValue(i);
    progressDialog.setLabelText(tr("%1 Coping file number %2 of %3 ")
        .arg((conf->isConsole) ? tr("Making copy of the Alta-GTD\n") : "")
        .arg(i + 1)
        .arg(gtdStringList.count()));

    qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

    if (progressDialog.wasCanceled()) {

        // removing tmp files/folders
        rmDirectoryRecursive(tmpFolder);
        rmDirectoryRecursive(tmpFolderPlus);
        setEnableGUI(true);
        return;
    }

    // coping
    if (!QFile::copy(gtdStringList.at(i), tmpStringList.at(i))) {

        if (warningFlag) {

            QMessageBox box(this);
            QString name = tr("Question");
            QString file1 = getShortName(gtdStringList.at(i), QString("\\...\\"));
            QString file2 = getShortName(tmpStringList.at(i), QString("\\...\\"));
            QString text = tr("Cannot copy <b>%1</b> <p>to <b>%2</b>"   \
               "<p>This file will be ignored, just press <b>Yes</b> button" \
               "<p>Press <b>YesToAll</b> button to ignore other warnings automatically..."  \
               "<p>Or press <b>Abort</b> to cancel operation").arg(file1).arg(file2);

            box.setModal(true);
            box.setWindowTitle(name);
            box.setText(QString::fromLatin1("%1").arg(text));
            box.setIcon(QMessageBox::Question);
            box.setStandardButtons(QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::Abort);

            switch (box.exec()) {                   
                case (QMessageBox::YesToAll):
                    warningFlag = false;
                    break;
                case (QMessageBox::Yes):
                    break;
                case (QMessageBox::Abort):
                    rmDirectoryRecursive(tmpFolder);
                    rmDirectoryRecursive(tmpFolderPlus);
                    setEnableGUI(true);
                    return;
            }
        }
    }
}

And that's all. Good luck!

揽月 2024-09-02 12:41:42

我想要类似的东西,并且在谷歌上搜索(徒劳),所以这就是我必须做的:

static bool cpDir(const QString &srcPath, const QString &dstPath)
{
    rmDir(dstPath);
    QDir parentDstDir(QFileInfo(dstPath).path());
    if (!parentDstDir.mkdir(QFileInfo(dstPath).fileName()))
        return false;

    QDir srcDir(srcPath);
    foreach(const QFileInfo &info, srcDir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
        QString srcItemPath = srcPath + "/" + info.fileName();
        QString dstItemPath = dstPath + "/" + info.fileName();
        if (info.isDir()) {
            if (!cpDir(srcItemPath, dstItemPath)) {
                return false;
            }
        } else if (info.isFile()) {
            if (!QFile::copy(srcItemPath, dstItemPath)) {
                return false;
            }
        } else {
            qDebug() << "Unhandled item" << info.filePath() << "in cpDir";
        }
    }
    return true;
}

它使用看起来非常相似的 rmDir 函数:

static bool rmDir(const QString &dirPath)
{
    QDir dir(dirPath);
    if (!dir.exists())
        return true;
    foreach(const QFileInfo &info, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
        if (info.isDir()) {
            if (!rmDir(info.filePath()))
                return false;
        } else {
            if (!dir.remove(info.fileName()))
                return false;
        }
    }
    QDir parentDir(QFileInfo(dirPath).path());
    return parentDir.rmdir(QFileInfo(dirPath).fileName());
}

这不处理链接和特殊文件,顺便提一句。

I wanted something similar, and was googling (in vain), so this is where I've got to:

static bool cpDir(const QString &srcPath, const QString &dstPath)
{
    rmDir(dstPath);
    QDir parentDstDir(QFileInfo(dstPath).path());
    if (!parentDstDir.mkdir(QFileInfo(dstPath).fileName()))
        return false;

    QDir srcDir(srcPath);
    foreach(const QFileInfo &info, srcDir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
        QString srcItemPath = srcPath + "/" + info.fileName();
        QString dstItemPath = dstPath + "/" + info.fileName();
        if (info.isDir()) {
            if (!cpDir(srcItemPath, dstItemPath)) {
                return false;
            }
        } else if (info.isFile()) {
            if (!QFile::copy(srcItemPath, dstItemPath)) {
                return false;
            }
        } else {
            qDebug() << "Unhandled item" << info.filePath() << "in cpDir";
        }
    }
    return true;
}

It uses an rmDir function that looks pretty similar:

static bool rmDir(const QString &dirPath)
{
    QDir dir(dirPath);
    if (!dir.exists())
        return true;
    foreach(const QFileInfo &info, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
        if (info.isDir()) {
            if (!rmDir(info.filePath()))
                return false;
        } else {
            if (!dir.remove(info.fileName()))
                return false;
        }
    }
    QDir parentDir(QFileInfo(dirPath).path());
    return parentDir.rmdir(QFileInfo(dirPath).fileName());
}

This doesn't handle links and special files, btw.

把人绕傻吧 2024-09-02 12:41:42

艰难的方式。单独复制每个文件。

  • 使用 QDir::entryList() 迭代目录的内容
  • 使用 QDir::cd()QDir::cdUp()进出目录
  • 使用 QDir::mkdir() 和 QDir::mkpath() 来创建新的文件夹树
  • ,最后使用 QFile: :copy() 复制实际文件

The hard way. Copy every file individually.

  • Use QDir::entryList() to iterate over the content of a directory
  • Use QDir::cd() and QDir::cdUp() to go in and out of directories
  • Use QDir::mkdir() and QDir::mkpath() to create the new folders tree
  • and finally, use QFile::copy() to copy the actual files
青春有你 2024-09-02 12:41:42

这基本上是 petch 的答案,由于它在 Qt 5.6 中对我造成了破坏,因此略有变化(这是最热门的问题) ,因此所有功劳都归于 petch

功能

bool copyPath(QString sourceDir, QString destinationDir, bool overWriteDirectory)
{
    QDir originDirectory(sourceDir);

    if (! originDirectory.exists())
    {
        return false;
    }

    QDir destinationDirectory(destinationDir);

    if(destinationDirectory.exists() && !overWriteDirectory)
    {
        return false;
    }
    else if(destinationDirectory.exists() && overWriteDirectory)
    {
        destinationDirectory.removeRecursively();
    }

    originDirectory.mkpath(destinationDir);

    foreach (QString directoryName, originDirectory.entryList(QDir::Dirs | \
                                                              QDir::NoDotAndDotDot))
    {
        QString destinationPath = destinationDir + "/" + directoryName;
        originDirectory.mkpath(destinationPath);
        copyPath(sourceDir + "/" + directoryName, destinationPath, overWriteDirectory);
    }

    foreach (QString fileName, originDirectory.entryList(QDir::Files))
    {
        QFile::copy(sourceDir + "/" + fileName, destinationDir + "/" + fileName);
    }

    /*! Possible race-condition mitigation? */
    QDir finalDestination(destinationDir);
    finalDestination.refresh();

    if(finalDestination.exists())
    {
        return true;
    }

    return false;
}

用途:

/*! Overwrite existing directories. */
bool directoryCopied = copyPath(sourceDirectory, destinationDirectory, true);

/*! Do not overwrite existing directories. */
bool directoryCopied = copyPath(sourceDirectory, destinationDirectory, false);

This is basically petch's answer with a slight change due to it breaking for me in Qt 5.6 (this is the top question hit), so all credit goes to petch.

function

bool copyPath(QString sourceDir, QString destinationDir, bool overWriteDirectory)
{
    QDir originDirectory(sourceDir);

    if (! originDirectory.exists())
    {
        return false;
    }

    QDir destinationDirectory(destinationDir);

    if(destinationDirectory.exists() && !overWriteDirectory)
    {
        return false;
    }
    else if(destinationDirectory.exists() && overWriteDirectory)
    {
        destinationDirectory.removeRecursively();
    }

    originDirectory.mkpath(destinationDir);

    foreach (QString directoryName, originDirectory.entryList(QDir::Dirs | \
                                                              QDir::NoDotAndDotDot))
    {
        QString destinationPath = destinationDir + "/" + directoryName;
        originDirectory.mkpath(destinationPath);
        copyPath(sourceDir + "/" + directoryName, destinationPath, overWriteDirectory);
    }

    foreach (QString fileName, originDirectory.entryList(QDir::Files))
    {
        QFile::copy(sourceDir + "/" + fileName, destinationDir + "/" + fileName);
    }

    /*! Possible race-condition mitigation? */
    QDir finalDestination(destinationDir);
    finalDestination.refresh();

    if(finalDestination.exists())
    {
        return true;
    }

    return false;
}

Use:

/*! Overwrite existing directories. */
bool directoryCopied = copyPath(sourceDirectory, destinationDirectory, true);

/*! Do not overwrite existing directories. */
bool directoryCopied = copyPath(sourceDirectory, destinationDirectory, false);
梦醒时光 2024-09-02 12:41:42

试试这个:

bool copyDirectoryFiles(const QString &fromDir, const QString &toDir, bool coverFileIfExist)
{
    QDir sourceDir(fromDir);
    QDir targetDir(toDir);
    if(!targetDir.exists()){    /* if directory don't exists, build it */
        if(!targetDir.mkdir(targetDir.absolutePath()))
            return false;
    }

    QFileInfoList fileInfoList = sourceDir.entryInfoList();
    foreach(QFileInfo fileInfo, fileInfoList){
        if(fileInfo.fileName() == "." || fileInfo.fileName() == "..")
            continue;

        if(fileInfo.isDir()){    /* if it is directory, copy recursively*/
            if(!copyDirectoryFiles(fileInfo.filePath(),  
                targetDir.filePath(fileInfo.fileName()), 
                coverFileIfExist)) 
                return false;
        }
        else{            /* if coverFileIfExist == true, remove old file first */
            if(coverFileIfExist && targetDir.exists(fileInfo.fileName())){
                targetDir.remove(fileInfo.fileName());
            }

            // files copy
            if(!QFile::copy(fileInfo.filePath(),  
                targetDir.filePath(fileInfo.fileName()))){ 
                    return false;
            }
        }
    }
    return true;
}

Try this:

bool copyDirectoryFiles(const QString &fromDir, const QString &toDir, bool coverFileIfExist)
{
    QDir sourceDir(fromDir);
    QDir targetDir(toDir);
    if(!targetDir.exists()){    /* if directory don't exists, build it */
        if(!targetDir.mkdir(targetDir.absolutePath()))
            return false;
    }

    QFileInfoList fileInfoList = sourceDir.entryInfoList();
    foreach(QFileInfo fileInfo, fileInfoList){
        if(fileInfo.fileName() == "." || fileInfo.fileName() == "..")
            continue;

        if(fileInfo.isDir()){    /* if it is directory, copy recursively*/
            if(!copyDirectoryFiles(fileInfo.filePath(),  
                targetDir.filePath(fileInfo.fileName()), 
                coverFileIfExist)) 
                return false;
        }
        else{            /* if coverFileIfExist == true, remove old file first */
            if(coverFileIfExist && targetDir.exists(fileInfo.fileName())){
                targetDir.remove(fileInfo.fileName());
            }

            // files copy
            if(!QFile::copy(fileInfo.filePath(),  
                targetDir.filePath(fileInfo.fileName()))){ 
                    return false;
            }
        }
    }
    return true;
}
橘味果▽酱 2024-09-02 12:41:42

我制作了一个库来通过 shell 命令风格的 API 来操作文件。它支持文件的递归复制并处理更多条件。

https://github.com/benlau/qtshell#cp

示例

cp("-a", ":/*", "/target"); // copy all files from qrc resource to target path recursively

cp("tmp.txt", "/tmp");

cp("*.txt", "/tmp");

cp("/tmp/123.txt", "456.txt");

cp("-va","src/*", "/tmp");

cp("-a", ":resource","/target");

I have made a library to manipulate files by a shell command style API. It supports a recursively copy of files and handled several more conditions.

https://github.com/benlau/qtshell#cp

Example

cp("-a", ":/*", "/target"); // copy all files from qrc resource to target path recursively

cp("tmp.txt", "/tmp");

cp("*.txt", "/tmp");

cp("/tmp/123.txt", "456.txt");

cp("-va","src/*", "/tmp");

cp("-a", ":resource","/target");
遗弃M 2024-09-02 12:41:42

由于我在 macOS 上使用 App-Bundles 时遇到了一些问题,这里有一个使用 QDirIterator 的解决方案

void copyAndReplaceFolderContents(const QString &fromDir, const QString &toDir, bool copyAndRemove = false) {
QDirIterator it(fromDir, QDirIterator::Subdirectories);
QDir dir(fromDir);
const int absSourcePathLength = dir.absoluteFilePath(fromDir).length();

while (it.hasNext()){
    it.next();
    const auto fileInfo = it.fileInfo();
    if(!fileInfo.isHidden()) { //filters dot and dotdot
        const QString subPathStructure = fileInfo.absoluteFilePath().mid(absSourcePathLength);
        const QString constructedAbsolutePath = toDir + subPathStructure;
        
        if(fileInfo.isDir()){
            //Create directory in target folder
            dir.mkpath(constructedAbsolutePath);
        } else if(fileInfo.isFile()) {
            //Copy File to target directory

            //Remove file at target location, if it exists. Otherwise QFile::copy will fail
            QFile::remove(constructedAbsolutePath);
            QFile::copy(fileInfo.absoluteFilePath(), constructedAbsolutePath);
        }
    }
}

if(copyAndRemove)
    dir.removeRecursively();

}

Since I had some trouble with App-Bundles on macOS, here's a solution with QDirIterator

void copyAndReplaceFolderContents(const QString &fromDir, const QString &toDir, bool copyAndRemove = false) {
QDirIterator it(fromDir, QDirIterator::Subdirectories);
QDir dir(fromDir);
const int absSourcePathLength = dir.absoluteFilePath(fromDir).length();

while (it.hasNext()){
    it.next();
    const auto fileInfo = it.fileInfo();
    if(!fileInfo.isHidden()) { //filters dot and dotdot
        const QString subPathStructure = fileInfo.absoluteFilePath().mid(absSourcePathLength);
        const QString constructedAbsolutePath = toDir + subPathStructure;
        
        if(fileInfo.isDir()){
            //Create directory in target folder
            dir.mkpath(constructedAbsolutePath);
        } else if(fileInfo.isFile()) {
            //Copy File to target directory

            //Remove file at target location, if it exists. Otherwise QFile::copy will fail
            QFile::remove(constructedAbsolutePath);
            QFile::copy(fileInfo.absoluteFilePath(), constructedAbsolutePath);
        }
    }
}

if(copyAndRemove)
    dir.removeRecursively();

}

暮倦 2024-09-02 12:41:42

如果您使用的是基于 Linux 的系统,并且 cp 命令存在并且可以运行,那么您可以使用 QProcess 启动 bash:

auto copy = new QProcess(this);
copy->start(QStringLiteral("cp -rv %1 %2").arg(sourceFolder, destinationFolder));
copy->waitForFinished();
copy->close();

cp 详细信息:

  • - r 表示递归
  • -v 表示打印成功复制的文件

注意:如果复制操作很长,那么您需要管理 UI 冻结,如前所述此处

If you are on a linux based system and the cp command exists and can be run, then you can use a QProcess to launch a bash:

auto copy = new QProcess(this);
copy->start(QStringLiteral("cp -rv %1 %2").arg(sourceFolder, destinationFolder));
copy->waitForFinished();
copy->close();

cp details:

  • -r means recursively
  • -v means it prints the successfully copied file

Note: if the copy operation is long, then you need to managed the UI freezing, as noted here

落花浅忆 2024-09-02 12:41:42
  • 假设目标位置为空“没有现有文件或文件夹
    具有相同的名称”
    并且使用递归没有问题
    功能!! 那么代码将是这样的,

void copy_all(QString dst_loc, QString src_loc)
{
    QDir src(src_loc);
    for(QFileInfo file_info : src.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot)){
        if(file_info.isDir()){
            src.mkpath(dst_loc+'/'+file_info.fileName());
            copy_all(dst_loc+'/'+file_info.fileName(),file_info.absoluteFilePath());
        }
        QFile::copy(file_info.absoluteFilePath(), dst_loc+'/'+file_info.fileName());
    }
}

递归地复制目录,那么如果您曾经处理过树数据结构并尝试创建一个递归函数来执行“深度优先搜索”算法, 您将得到一个< strong>85%相似的算法,实际上我就是从中得到这个想法的。

  • 第二种方法是使用地图数据结构来保存当前
    目录中的fileInfoList,以及相应的状态来显示if
    您是否已经使用过此文件信息。你收集所有
    首先是有关源位置的子目录和文件的信息。

这就是大多数操作系统和其他文件管理器复制数据的方式,通过显示要复制的文件的大小、要复制的文件和文件夹的数量,以及最后是否存在文件或文件夹冲突甚至在开始复制之前就使用相同的名称“如果您将对目标执行相同的算法,以便可以匹配文件名”。

祝你好运!。

  • Assuming the target location is empty "no existing files or folders
    with the same names"
    and you have no problem to use a Recursive
    function!! to copy a directory recursively then the code will be something like this

void copy_all(QString dst_loc, QString src_loc)
{
    QDir src(src_loc);
    for(QFileInfo file_info : src.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot)){
        if(file_info.isDir()){
            src.mkpath(dst_loc+'/'+file_info.fileName());
            copy_all(dst_loc+'/'+file_info.fileName(),file_info.absoluteFilePath());
        }
        QFile::copy(file_info.absoluteFilePath(), dst_loc+'/'+file_info.fileName());
    }
}

if you ever dealt with tree data structures and tried to create a Recursive function to do a "depth-first search" Alogorithm you will get a 85% similar algorithm, which Actually I got this idea from.

  • The second way, is by using a map data structure to hold the current
    fileInfoList in a directory, and the corresponding state to show if
    you have used this fileInfo or not yet. and you gather all
    information firstly about sub directories and files from the source location.

And this is how most OS and other file managers do to copy data, by showing you the size of files to be copied, how many files and folders are going to be copied, and finally, if there is any conflict of files or folders with the same name before you even initiate copying "if you will do the same algorithm with the destination so that you can match filenames".

Good luck!.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文