From 10a8921bbcd9802ad2425e8cee1e5ca70fb0b241 Mon Sep 17 00:00:00 2001 From: Arno Date: Wed, 13 Jun 2018 09:27:59 +0200 Subject: Speed up file copy Hmm, as it turns out QFile does a much better, e.g. faster, job than my open-coded file copy with a progress dialog. I always wondered why it only did 150-170Mbit. I thought that it was just the calculation, but now I have 400 Mbit, and it still stalls at 150 Mbit. QFile::copy maxes out the line, so get rid of the ProgressDialog and show a status message instead. Copy can be canceled by the context menu, but FileCopier will always finish the current file, because I don't want to lock and unlock the CancelMutex during copy. Besides, QFile::copy doesn't admit that :) --- ShemovCleaner.pro | 2 -- filecopier.cpp | 61 +++++++++++++----------------------------------------- filecopier.h | 5 +---- filewidget.cpp | 46 ++++++---------------------------------- filewidget.h | 7 +------ progressdialog.cpp | 40 ----------------------------------- progressdialog.h | 34 ------------------------------ 7 files changed, 22 insertions(+), 173 deletions(-) delete mode 100644 progressdialog.cpp delete mode 100644 progressdialog.h diff --git a/ShemovCleaner.pro b/ShemovCleaner.pro index 8f59657..efdd964 100644 --- a/ShemovCleaner.pro +++ b/ShemovCleaner.pro @@ -29,7 +29,6 @@ HEADERS += \ globals.h \ helper.h \ origindialog.h \ - progressdialog.h \ shemovcleaner.h \ torrentdisplay.h \ torrentparser.h \ @@ -49,7 +48,6 @@ SOURCES += \ helper.cpp \ main.cpp \ origindialog.cpp \ - progressdialog.cpp \ shemovcleaner.cpp \ torrentdisplay.cpp \ torrentparser.cpp \ diff --git a/filecopier.cpp b/filecopier.cpp index 1588d6e..6256be1 100644 --- a/filecopier.cpp +++ b/filecopier.cpp @@ -1,6 +1,5 @@ #include #include -#include #include "filecopier.h" @@ -15,11 +14,8 @@ void FileCopier::addJob(const QString &source, const QString &dest){ } void FileCopier::run(){ - int bufsize = 32 * 1024 * 1024; - char *buf = new char[bufsize]; mCancel = false; mCopied = 0; - QElapsedTimer et; while(!mJobs.isEmpty()){ mAddJobMutex.lock(); auto first = mJobs.constBegin(); @@ -27,58 +23,29 @@ void FileCopier::run(){ auto dest = first.value(); mJobs.remove(source); mAddJobMutex.unlock(); + QString msg = QString(tr("Copy: %1 (%2/%3)")).arg(source).arg(QString::number(mCopied + 1)).arg(QString::number(mTotal)); + emit message(msg); QFile sFile(source); - QFile dFile(dest); - bool openSource = sFile.open(QIODevice::ReadOnly); - bool openDest = dFile.open(QIODevice::WriteOnly); - if(!openSource || !openDest){ - emit success(false, source); - goto cleanup; + if(sFile.copy(dest)){ + ++mCopied; + QString msg = QString(tr("Copied file %1/%2").arg(QString::number(mCopied)).arg(QString::number(mTotal))); + emit message(msg); + }else{ + QString msg = QString(tr("Failed to copy %1: %2").arg(source).arg(sFile.errorString())); + emit message(msg); } - emit newFile(source, dest, sFile.size()); - int read = 0; - qint64 total = 0; - qint64 elapsed = 0; - qint64 bytesSinceEl = 0; - et.start(); - while(!sFile.atEnd()){ - read = sFile.read(buf, bufsize); - dFile.write(buf, read); - total += read; - bytesSinceEl += read; - elapsed = et.elapsed(); - if(elapsed > 1000){ - mCancelMutex.lock(); - bool cancel = mCancel; - mCancelMutex.unlock(); - if(cancel){ - dFile.close(); - QFile::remove(dest); - emit success(false, source); - goto cleanup; - } - mCountMutex.lock(); - emit bytesReadIntval(bytesSinceEl, elapsed, mTotal, mCopied); - mCountMutex.unlock(); - elapsed = 0; - bytesSinceEl = 0; - et.restart(); - } - emit bytesRead(total); + QMutexLocker l(&mCancelMutex); + if(mCancel){ + break; } - emit success(true, source); - ++mCopied; - emit bytesReadIntval(bytesSinceEl, elapsed, mTotal, mCopied); - et.restart(); } - - cleanup: - delete buf; + mCancel = false; mTotal = 0; mJobs.clear(); } void FileCopier::cancel(){ QMutexLocker l(&mCancelMutex); + emit message(tr("Canceling copy jobs. Please wait...")); mCancel = true; } diff --git a/filecopier.h b/filecopier.h index 6a9e37f..12aa3ac 100644 --- a/filecopier.h +++ b/filecopier.h @@ -14,10 +14,7 @@ class FileCopier : public QThread { void cancel(); signals: - void newFile(const QString &source, const QString & dest, qint64 size); - void success(bool s, QString source); - void bytesRead(qint64 bytes); - void bytesReadIntval(qint64 bytes, qint64 msecs, int total, int copied); + void message(const QString &msg); private: QHash mJobs; diff --git a/filewidget.cpp b/filewidget.cpp index 7a7e361..d1600f6 100644 --- a/filewidget.cpp +++ b/filewidget.cpp @@ -46,20 +46,13 @@ #include "helper.h" #include "globals.h" #include "viewer.h" -#include "progressdialog.h" #include "searchdialog.h" FileWidget::FileWidget(QWidget *parent) : QWidget(parent), mCopyToMenu(0) { mFileCopier = new FileCopier(this); - mCopyProgress = new ProgressDialog; mFileCache.setMaxCost(500); readCache(); - connect(mFileCopier, &FileCopier::newFile, this, &FileWidget::setupProgress); - connect(mFileCopier, &FileCopier::bytesRead, this, &FileWidget::setCopyProgress); - connect(mFileCopier, &FileCopier::bytesReadIntval, this, &FileWidget::setCopySummary); - connect(mFileCopier, &FileCopier::finished, this, &FileWidget::hideCopyProgress); - connect(mFileCopier, &FileCopier::success, this, &FileWidget::copySuccess); - connect(mCopyProgress, &ProgressDialog::cancelled, this, &FileWidget::hideCopyProgress); + connect(mFileCopier, &FileCopier::message, this, &FileWidget::statusMessage); setupGui(); } @@ -146,7 +139,6 @@ void FileWidget::setupGui(){ createActions(); mMimeData = new QMimeData; mFileView->setFocus(); - mCopyProgress->setVisible(false); QSettings s; QString startMimeFilter = s.value("currentmimefilter").toString(); @@ -196,6 +188,8 @@ void FileWidget::createActions(){ connect(searchGoogleA, &QAction::triggered, this, &FileWidget::searchGoogle); QAction *searchDlgA = new QAction(QIcon(":/system-search.png"), tr("Search dialog..."), this); connect(searchDlgA, &QAction::triggered, mSearchDlg, &SearchDialog::show); + mCancelCopyA = new QAction(QIcon(":/chastity_belt.png"), tr("Cancel copy"), this); + connect(mCancelCopyA, &QAction::triggered, mFileCopier, &FileCopier::cancel); QMenu *fileMenu = new QMenu(tr("&File")); fileMenu->addAction(mSelDirA); @@ -704,29 +698,6 @@ void FileWidget::addAsOrigin(){ mOrignDlg->show(); } -void FileWidget::setupProgress(QString file, QString dest, qint64 size){ - mCopyProgress->setMaximum(size / 1024 / 1024); - mCopyProgress->setValue(0); - QFileInfo fi(file); - QString srcLabel = QString(tr("Copying %1")).arg(fi.fileName()); - QFileInfo fi2(dest); - QString dstLabel = QString(tr("to %2")).arg(QDir::toNativeSeparators(fi2.absolutePath())); - mCopyProgress->setLabelText(srcLabel, dstLabel); -} - -void FileWidget::setCopyProgress(qint64 bytes){ - int val = bytes / 1024 / 1024; - mCopyProgress->setValue(val); -} - -void FileWidget::setCopySummary(qint64 bytes, qint64 elapsed, int total, int copying){ - if(elapsed != 0){ - float rate = bytes * 8 / (elapsed / 1000.0) / 1024 / 1024.0; - QString sum = QString("%1/%2 file(s), @ %3 MB/s").arg(QString::number(copying+1)).arg(QString::number(total)).arg(QString::number(rate, 'f', 2)); - mCopyProgress->setSummary(sum); - } -} - void FileWidget::copyFiles(QString destDir){ QModelIndexList files = mFileView->selectionModel()->selectedRows(); if(!files.isEmpty()){ @@ -739,20 +710,12 @@ void FileWidget::copyFiles(QString destDir){ QString destFile = QString("%1%2%3").arg(destDir).arg(QDir::separator()).arg(fi.fileName()); mFileCopier->addJob(fp, destFile); } - mCopyProgress->show(); if(!mFileCopier->isRunning()){ mFileCopier->start(); } } } -void FileWidget::hideCopyProgress(){ - if(mFileCopier->isRunning()){ - mFileCopier->cancel(); - } - mCopyProgress->hide(); -} - void FileWidget::copySuccess(bool success, QString source){ if(success){ QFileInfo fi(source); @@ -980,6 +943,9 @@ void FileWidget::contextMenuEvent(QContextMenuEvent *e){ } } contextMenu.addMenu(mCopyToMenu); + if(mFileCopier->isRunning()){ + contextMenu.addAction(mCancelCopyA); + } contextMenu.addAction(createSeparator()); contextMenu.addActions(actions()); contextMenu.exec(e->globalPos()); diff --git a/filewidget.h b/filewidget.h index 850cc6f..0b11d0e 100644 --- a/filewidget.h +++ b/filewidget.h @@ -23,7 +23,6 @@ class FileDisplay; class OriginDialog; class QMenu; class FileCopier; -class ProgressDialog; class CachedFileData; class QStandardItem; class QComboBox; @@ -72,11 +71,7 @@ class FileWidget : public QWidget { void paste(); void selectFirst(); void addAsOrigin(); - void setupProgress(QString file, QString dest, qint64 size); - void setCopyProgress(qint64 bytes); - void setCopySummary(qint64 bytes, qint64 elapsed, int total, int copying); void copyFiles(QString destDir); - void hideCopyProgress(); void copySuccess(bool success, QString source); void removeFromCache(); void clearCache(); @@ -128,7 +123,7 @@ class FileWidget : public QWidget { QAction *mRemoveFromCacheA; QAction *mClearCacheA; QAction *mGuessSubjectA; - ProgressDialog *mCopyProgress; + QAction *mCancelCopyA; FileDisplay *mFileDisplay; VideoSorter *mProxy; OriginDialog *mOrignDlg; diff --git a/progressdialog.cpp b/progressdialog.cpp deleted file mode 100644 index 0690d65..0000000 --- a/progressdialog.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include - -#include "progressdialog.h" - -ProgressDialog::ProgressDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f){ - mSrc = new QLabel; - mDst = new QLabel; - mProgress = new QProgressBar; - mSum = new QLabel(tr("Wait for it...")); - QPushButton *cancelBtn = new QPushButton(tr("Cancel")); - connect(cancelBtn, &QPushButton::clicked, this, &ProgressDialog::cancelled); - QHBoxLayout *btnLayout = new QHBoxLayout; - btnLayout->addStretch(); - btnLayout->addWidget(cancelBtn); - btnLayout->addStretch(); - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(mSrc); - mainLayout->addWidget(mDst); - mainLayout->addWidget(mProgress); - mainLayout->addWidget(mSum); - mainLayout->addLayout(btnLayout); - setMaximumWidth(400); - setMinimumWidth(400); - setLayout(mainLayout); -} - -void ProgressDialog::setLabelText(const QString &src, const QString &dst){ - QFontMetrics fm(mSrc->font()); - int width = mSrc->width() - 4; - QString srcElided = fm.elidedText(src, Qt::ElideRight, width); - mSrc->setText(srcElided); - QString dstElided = fm.elidedText(dst, Qt::ElideRight, width); - mDst->setText(dstElided); -} - -void ProgressDialog::setValue(int val){ - mProgress->setValue(val); -} diff --git a/progressdialog.h b/progressdialog.h deleted file mode 100644 index 01657c8..0000000 --- a/progressdialog.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef PROGRESSDIALOG_H -#define PROGRESSDIALOG_H - -#include -#include -#include - -class ProgressDialog : public QDialog { - Q_OBJECT - public: - ProgressDialog(QWidget *parent = 0, Qt::WindowFlags f = 0); - void setLabelText(const QString &src, const QString &dst); - void setMaximum(int max) { mProgress->setMaximum(max); } - void setSummary(const QString &sum) { mSum->setText(sum); } - - public slots: - void setValue(int val); - void setTotal(int total) { mTotal = total; } - void setCopied(int copied) { mCopied = copied; } - - signals: - void cancelled(); - - private: - QLabel *mSrc; - QLabel *mDst; - QLabel *mSum; - QProgressBar *mProgress; - int mTotal; - int mCopied; - -}; - -#endif // PROGRESSDIALOG_H -- cgit v1.2.3-70-g09d2