具有进度和传输速率/速度的 PyQt 复制文件夹
Posted
技术标签:
【中文标题】具有进度和传输速率/速度的 PyQt 复制文件夹【英文标题】:PyQt Copy folder with progress and transfer rate/speed 【发布时间】:2017-06-07 11:14:56 【问题描述】:我想扩展我当前的代码,使其能够显示正在复制的文件的传输速率/速度。我正在使用 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 rate
、time elapsed
和time 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()
【问题讨论】:
一种简单的方法是只计算文件数并以此方式显示进度,或者计算总大小并使用文件大小来显示进度。我猜如果您不自己打开并复制文件,您将无法轻松显示单个大文件的进度.. 我已经统计了文件,见方法def countfiles
。进度很好,我只想显示传输速度,例如15 MB /s
要显示整体传输速度,您可以计算到要复制的文件的总文件大小(我想如果您已经计算过它们并且可以访问循环)并将其除以使用的时间!?或者如果您只考虑文件的最后一分钟等,则显示当前速度,这取决于文件大小和内容,如果您无法访问单个文件的副本,则很难获得更精确的信息?
我重新考虑了理论部分:我只需要在特定的时间间隔内读取复制的文件大小 -> 每 1 分钟检查一次复制的文件并计算大小,例如1 分钟内 50 MB (50 MB / 60s = 0.83 MB/s) 还是我错过了什么?但是间隔呢,我该怎么做呢??
【参考方案1】:
这都是关于逻辑的,请按照以下方式思考:
-
您有所有文件的总大小,假设您有 100 个破折号:[----- ... -----]
现在您将获得开始传输文件的开始时间。
选择一些间隔,例如 2 秒。
因此,在 2 秒后查看您已经传输了多少文件,换句话说,您在新目录中已有多少文件。假设您转移了 26 个破折号。
计算结果为 26 次/2 秒 = 13 次/秒。
再深入一点,我们在 2 秒内下载了 26% 的内容,因为总量为每秒 100 或 13%。
更进一步,我们还可以计算时间预测。
总时间 = 100%/13% = 7.6 秒
经过的时间 = 2 秒
剩余时间 = 7.6 - 2 = 5.6 秒
我想你明白了……
注意:如果您当然选择 2 秒,您只需要在每 2 秒内继续验证和重新制作所有这些计算,并将信息更新给用户。如果您想更精确或向用户显示更频繁更新的信息,只需将该间隔缩短到 0.5 秒,并将计算时间设置为毫秒。更新信息的频率取决于您,这只是对如何进行数学计算的概述。 ")
【讨论】:
以上是关于具有进度和传输速率/速度的 PyQt 复制文件夹的主要内容,如果未能解决你的问题,请参考以下文章