2010-03-29 21 views
18

Desidero copiare una directory da un'unità a un'altra. La mia directory selezionata contiene molte sottodirectory e file.Copia directory utilizzando Qt

Come posso implementare lo stesso utilizzando Qt?

risposta

6

Il modo difficile. Copia ogni singolo file.

  • Usa QDir::entryList() per scorrere il contenuto di una directory
  • Usa QDir::cd() e QDir::cdUp() di andare dentro e fuori di directory
  • Usa QDir::mkdir() e QDir::mkpath() per creare il nuovo albero delle cartelle
  • e, infine, l'uso QFile::copy() per copiare i file attuali
12

Manualmente, puoi fare le seguenti cose:

1). con func sotto puoi generare cartelle/lista di file (in modo ricorsivo) - i file di destinazione.

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). allora si può iniziare a copiare i file dalla destinazione lista alla nuova directory di origine del genere:

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; 
      } 
     } 
    } 
} 

E questo è tutto. In bocca al lupo!

+1

ho provato distacco mia correzione come una modifica, ma nessuno sembra capirlo, così ho posterò qui. usando 'QString ("% 1 /% 2 "). arg (d.path()). arg (file)' generalmente non è una buona idea visto come '% 1' o '% 2' può essere trovato (in più filesystem) in un nome di file o percorso. prendi questo percorso creato da cygwin come esempio 'c: \ cyg \ ftp% 3a% 2f% 2fcygwin.mirrorcatalogs.com% 2fcygwin% 2f'. – vikki

+3

diciamo che questo è ciò che viene tenuto in 'd.path()' e 'file' ha' text.txt'. '% 1' sarà sostituito da 'd.path()' per formare 'c: \ cyg \ ftp% 3a% 2f% 2fcygwin.mirrorcatalogs.com% 2fcygwin% 2f /% 2'. infine avrai 'c: \ cyg \ ftp% 3atext.txtftext.txtfcygwin.mirrorcatalogs.comtext.txtfcygwintext.txtf/text.txt'. un'opzione migliore è 'd.path(). append ('/'). append (file)' – vikki

+0

@vikki: Sì! Hai ragione! – mosg

5

Volevo qualcosa di simile, ed è stato googling (invano), quindi questo è dove ho avuto modo di:

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; 
} 

Si utilizza una funzione rmDir che sembra piuttosto simile:

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()); 
} 

Questo non gestisce collegamenti e file speciali, btw.

11
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); 
    } 
} 
+0

Non so se è il mio rig, o questo codice in Qt 5.6, ma questo codice sembra bloccarsi. Sta facendo la copia delle directory, ma non finisce mai. Strano. –

+0

Hm, sì. La prima operazione di copia funziona, quindi le copie successive stanno andando alle banane. Crea una dir, quindi copia quella dir in una sottodirectory. Prime opere, secondo, bang, morto. –

0

Questo è fondamentalmente petch's answer con un leggero cambiamento a causa di essa la rottura per me in Qt 5.6 (questo è il colpo domanda in alto), quindi tutto il merito va a petch.

funzione

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; 
} 

Usa:

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

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

Cosa c'è di diverso e perché? –

1

Prova questa:

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; 
} 
+0

Grazie per questo snippet di codice, che potrebbe fornire un aiuto immediato. Una spiegazione appropriata [migliorerebbe notevolmente] (// meta.stackexchange.com/q/114762) il suo valore educativo mostrando * perché * questa è una buona soluzione al problema e renderebbe più utile ai futuri lettori con simili, ma non identiche, domande. Si prega di [modificare] la risposta per aggiungere una spiegazione e fornire un'indicazione di quali limitazioni e ipotesi si applicano. –

1

Ho fatto una libreria per manipolare i file da un API shell dei comandi di stile. Supporta una copia ricorsiva di file e gestisce molte altre condizioni.

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

Esempio

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"); 
Problemi correlati