zoukankan      html  css  js  c++  java
  • 非常棒的进度条

    在ftp项目编写上传下载文件时候会用到进度条功能,以便客户机直观的获取文件传输状态信息。python已经由第三方tqdm库供我们调用了,但是这么一个简单的功能调用一个200多k的第三方模块让我觉得相当浪费,不如自己写一个吧!

    需求:

    require1>>>文件传输中,每当文件大小状态获得更新时,我需要在屏幕的进度条上得到实时反馈

    require2>>>我希望我的进度条能在一行展示,而不是铺满整个屏幕

    solve1:

    第一个需求让我想到生产者消费者模型,只是这里只有一个生产者和一个消费者

    solve2:

    print方法默认结束符end=' ',即下次打印会换行:

    import time
    
    
    for i in range(5):
        time.sleep(0.2)
        print(i)
    # 如下图,这种打印方式显然不符合要求

    而sys.stdout.write没有end一说,下次打印不会换行,更符合需求

    import sys
    import time
    
    
    for i in range(10):
        time.sleep(0.2)
        sys.stdout.write(str(i))
    # 如下图,这种方式能实现单行打印,但是为了
    提高效率,sys.stdout.write方法会等所有数据缓存满了再一次性输出,

    解决办法:sys.stdout.flush(),每来一次数据就强制输出一次,而不是默认所有数据一起输出

    import sys
    import time
    
    
    for i in range(10):
        time.sleep(0.2)
        sys.stdout.write(str(i))
        sys.stdout.flush()
    # 还是有问题:每次打印我只要从开始位置显示当前数据,之前数据不显示

    解决办法:在每次打印数据前加 ' ' 表示从当前行起始位置打印

    import sys
    import time
    
    
    for i in range(10):
        time.sleep(0.2)
        sys.stdout.write('
    ' + str(i))
        sys.stdout.flush()
    # 如下图,这样就比较完美了
    

     

    最终实现代码

    code1:

    # -*- coding:utf-8 -*-
    # Author: Tarantiner
    # @Time :2019/3/26 11:53
    
    import time
    import sys
    import queue
    from threading import Thread
    
    total_size = 36842  # 模拟文件总大小
    rec_size = 0  # 模拟接收到文件大小
    MAX = 50  # 进度条中显示最大方块数量
    
    
    def fetcher():
        # 实现进度条打印功能
        while True:
            k = q.get()
            if k is None:
                print(' Done!')
                break
            sys.stdout.write('
    ' + '|' + '▇' * k + '|' + str(int(k*100/MAX)) + '%')
    
    
    def producer(q):
        global rec_size
        count = 0
        while rec_size < total_size:
            time.sleep(0.1)
            rec_size += 1024  # 模拟获取数据
            count = int(rec_size * MAX / total_size)
            q.put(count)
        q.put(count)
        q.put(None) # 发送结束信号
    
    
    if __name__ == '__main__':
        q = queue.Queue()
        f = Thread(target=fetcher)
        f.start()
        producer(q)

    输出:

    想想code1中为单个生产者消费者开辟一个子线程,有点不值,于是又想到了生成器,实现单个线程下程序级别的切换,开销更小,于是就有了code2

    code2

    # -*- coding:utf-8 -*-
    # Author: Tarantiner
    # @Time :2019/3/26 12:25
    
    import time
    
    
    total_size = 100
    rec_size = 0
    count = 0
    
    
    def func():
        while True:
            k = yield
            # sys.stdout.write只是print的一种特定格式,那么print当然能实现sys.stdout.write功能
            print('
    ' + '|' + '▇'*k + '|' + str(k) + '%', end='', flush=True)
    
    
    f = func()
    next(f)
    while rec_size < total_size:
        f.send(count)
        time.sleep(0.2)
        rec_size += 2
        count = int(rec_size * 50 / total_size)
    f.send(count)
    

    至此,进度条问题就完美解决了,当然我会推荐code2使用生成器方式。

  • 相关阅读:
    C# Lambda表达式 (转)
    用C#读取txt文件的方法(转)
    c#中stringbuilder的使用(转)
    c# 日期和时间的获取(转)
    C# List<T>用法 泛型 (转)
    indent format codes
    格式化输入输出 小结
    putty connection manager 一些问题的整理
    linux 网络的一些书籍
    Oracle学习笔记
  • 原文地址:https://www.cnblogs.com/tarantino/p/10599899.html
Copyright © 2011-2022 走看看