具有进度和传输速率/速度的PyQt复制文件夹

时间:2017-06-07 11:14:56

标签: windows qt copy pyqt5 shutil

我想扩展当前的代码,能够显示正在复制的文件的传输速率/速度。我正在使用py 3.6和Qt 5.8在Windows 10上工作。这是我的代码:

import os
import shutil
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QProgressBar, QFileDialog

class FileCopyProgress(QWidget):


    def __init__(self, parent=None, src=None, dest=None):
        super(FileCopyProgress, self).__init__()

        self.src = src
        self.dest = dest
        self.build_ui()

    def build_ui(self):

        hbox = QVBoxLayout()

        lbl_src = QLabel('Source: ' + self.src)
        lbl_dest = QLabel('Destination: ' + self.dest)
        self.pb = QProgressBar()

        self.pb.setMinimum(0)
        self.pb.setMaximum(100)
        self.pb.setValue(0)

        hbox.addWidget(lbl_src)
        hbox.addWidget(lbl_dest)
        hbox.addWidget(self.pb)
        self.setLayout(hbox)

        self.setWindowTitle('File copy')
        self.auto_start_timer = QTimer()
        self.auto_start_timer.singleShot(2000, lambda: self.copyFilesWithProgress(self.src, self.dest, self.progress, self.copydone))
        self.show()

    def progress(self, done, total):
        progress = int(round((done/float(total))*100))

        try:
            self.pb.setValue(progress)
        except:
            pass

        app.processEvents()

    def copydone(self):
        self.pb.setValue(100)
        self.close()

    def countfiles(self, _dir):
        files = []

        if os.path.isdir(_dir):
            for path, dirs, filenames in os.walk(_dir):
                files.extend(filenames)
        return len(files)

    def makedirs(self, dest):
        if not os.path.exists(dest):
            os.makedirs(dest)

    @pyqtSlot()
    def copyFilesWithProgress(self, src, dest, callback_progress, callback_copydone):
        numFiles = self.countfiles(src)
        if numFiles > 0:
            dest = os.path.join(dest, src.replace(BASE_DIR, '').replace('\\', ''))
            print(''.join(['Destination: ', dest]))
            self.makedirs(dest)

            numCopied = 0
            for path, dirs, filenames in os.walk(src):
                for directory in dirs:
                    destDir = path.replace(src,dest)
                    self.makedirs(os.path.join(destDir, directory))
                for sfile in filenames:
                    srcFile = os.path.join(path, sfile)
                    destFile = os.path.join(path.replace(src, dest), sfile)
                    shutil.copy(srcFile, destFile)

                    numCopied += 1
                    callback_progress(numCopied, numFiles)
            callback_copydone()




BASE_DIR = 'C:\\dev'

app = QApplication([])
FileCopyProgress(src="C:\dev\pywin32-221", dest='C:\dev\copied')

# Run the app
app.exec_()

此代码打开一个gui,其中一个进度条显示复制文件时的进度。一个简单的标签与当前的传输速率/速度(近似)将是非常好的:)

不幸的是,我找不到任何例子,有人可以给我一个提示或可能是一个有效的例子吗?

修改: 我做了翻拍,现在我有transfer ratetime elapsedtime remaining。数据似乎是现实的。我只有一个问题:假设我有一个文件夹/文件time remaining是7秒 - >目前它以7秒开始,每1秒获得一次更新。我们希望在下一步它会显示6秒,但它会:   5秒   3秒   1.5秒   1.4秒   1.3秒   1.2秒   1.1秒等等

错误在哪里?

class FileCopyProgress(QWidget):

    def __init__(self, parent=None, src=None, dest=None):
        super(FileCopyProgress, self).__init__()

        self.src = src
        self.dest = dest
        self.rate = "0"
        self.total_time = "0 s"
        self.time_elapsed = "0 s"
        self.time_remaining = "0 s"
        self.build_ui()

    def build_ui(self):

        hbox = QVBoxLayout()

        lbl_src = QLabel('Source: ' + self.src)
        lbl_dest = QLabel('Destination: ' + self.dest)
        self.pb = QProgressBar()
        self.lbl_rate = QLabel('Transfer rate: ' + self.rate)
        self.lbl_time_elapsed = QLabel('Time Elapsed: ' + self.time_elapsed)
        self.lbl_time_remaining = QLabel('Time Remaining: ' + self.time_remaining)

        self.pb.setMinimum(0)
        self.pb.setMaximum(100)
        self.pb.setValue(0)

        hbox.addWidget(lbl_src)
        hbox.addWidget(lbl_dest)
        hbox.addWidget(self.pb)
        hbox.addWidget(self.lbl_rate)
        hbox.addWidget(self.lbl_time_elapsed)
        hbox.addWidget(self.lbl_time_remaining)
        self.setLayout(hbox)

        self.setWindowTitle('File copy')

        self.auto_start_timer = QTimer()
        self.auto_start_timer.singleShot(100, lambda: self.copy_files_with_progress(self.src, self.dest, self.progress, self.copy_done))

        self.copy_timer = QTimer()
        self.copy_timer.timeout.connect(lambda: self.process_informations())
        self.copy_timer.start(1000)
        self.show()

    @pyqtSlot()
    def process_informations(self):

        time_elapsed_raw = time.clock() - self.start_time
        self.time_elapsed = '{:.2f} s'.format(time_elapsed_raw)
        self.lbl_time_elapsed.setText('Time Elapsed: ' + self.time_elapsed)

        # example - Total: 100 Bytes, bisher kopiert 12 Bytes/s
        time_remaining_raw = self._totalSize/self._copied
        self.time_remaining = '{:.2f} s'.format(time_remaining_raw) if time_remaining_raw < 60. else '{:.2f} min'.format(time_remaining_raw)
        self.lbl_time_remaining.setText('Time Remaining: ' + self.time_remaining)

        rate_raw = (self._copied - self._copied_tmp)/1024/1024
        self.rate = '{:.2f} MB/s'.format(rate_raw)
        self.lbl_rate.setText('Transfer rate: ' + self.rate)

        self._copied_tmp = self._copied

    def progress(self):
        self._progress = (self._copied/self._totalSize)*100

        try:
            self.pb.setValue(self._progress)
        except:
            pass

        app.processEvents()

    def get_total_size(self, src):
        return sum( os.path.getsize(os.path.join(dirpath,filename)) for dirpath, dirnames, filenames in os.walk(src) for filename in filenames ) # total size of files in bytes

    def copy_done(self):
        self.pb.setValue(100)
        print("done")
        self.close()

    def make_dirs(self, dest):
        if not os.path.exists(dest):
            os.makedirs(dest)

    @pyqtSlot()
    def copy_files_with_progress(self, src, dst, callback_progress, callback_copydone, length=16*1024*1024):
        self._copied = 0
        self._copied_tmp = 0
        self._totalSize = self.get_total_size(src)

        print(''.join(['Pre Dst: ', dst]))

        dst = os.path.join(dst, src.replace(BASE_DIR, '').replace('\\', ''))

        print(''.join(['Src: ', src]))
        print(''.join(['Dst: ', dst]))
        self.make_dirs(dst)

        self.start_time = time.clock()
        for path, dirs, filenames in os.walk(src):
            for directory in dirs:
                destDir = path.replace(src, dst)
                self.make_dirs(os.path.join(destDir, directory))
            for sfile in filenames:
                srcFile = os.path.join(path, sfile)
                destFile = os.path.join(dst, sfile)
#                     destFile = os.path.join(path.replace(src, dst), sfile)

                with open(srcFile, 'rb') as fsrc:
                    with open(destFile, 'wb') as fdst:
                        while 1:
                            buf = fsrc.read(length)
                            if not buf:
                                break
                            fdst.write(buf)
                            self._copied += len(buf)
                            callback_progress()         
        try:
            self.copy_timer.stop()
        except:
            print('Error: could not stop QTimer')

        callback_copydone()

1 个答案:

答案 0 :(得分:0)

这完全与逻辑有关,请按以下方式思考:

  1. 你的所有文件都有一个总大小,让我们说你有100个破折号:[----- ... -----]
  2. 现在您可以获得开始传输文件的开始时间。
  3. 选择一些间隔,让我们有例如2秒。
  4. 因此,在2秒后看看你已经转移了多少,换句话说,你已经在新目录中拥有多少文件。让我们说你转了26个破折号。
  5. 计算结果为26个破折号/ 2秒= 13秒/秒。
  6. 我们在2秒内下载了26%的内容,因为总数是每秒100或13%。
  7. 我们还可以进一步预测时间。
  8. 总时间= 100%/ 13%= 7.6秒
  9. 经过的时间= 2秒
  10. 剩余时间= 7.6 - 2 = 5.6秒
  11. 我认为你有这个想法......

    注意:如果您选择2秒,并且将信息更新给用户,您只需每2秒钟验证并重新生成所有这些计算。如果您想要更精确或向用户显示更频繁更新的信息,只需减少该间隔,让其说0.5秒并使计算结果达到毫秒。由您更新信息的频率取决于您,这只是对如何进行数学运算的概述。 &#34)