• 请不要在回答技术问题时复制粘贴 AI 生成的内容
814084764
V2EX  ›  程序员

[速度 VS 准确] 下载时保存下载进度

  •  
  •   814084764 · Oct 13, 2016 · 4024 views
    This topic created in 3684 days ago, the information mentioned may be changed or developed.

    在写下载模块,遇到一个问题:下载的时候如何又快又准确地记录下载的进度?

    缘由:记录下载进度是为了下次继续下载时做文件校验,比如有没有被篡改。

    目前的方案:(伪代码)

    while(true)

    {

    byte[] buffer = connection.read();

    file.write(buffer);

    database.save(file.length());

    }

    出现一个问题:

    如果不加 database.save ,下载速度可以达到正常的带宽速度。

    如果加了,下载速度就会慢,并且很明显。

    但是为了做校验,肯定需要 [实时] 保存下载的文件大小。

    我想用一个 tempValue [实时] 记录一下进度,最后再刷到数据库中。

    但是有个问题:如果程序异常终止,就会导致 tempValue 没有被刷到数据库中。

    这样的话,有什么比较好的解决方案??

    14 replies  •  2016-10-14 10:03:11 +08:00
    bigboyq
    bigboyq
    Oct 13, 2016 via iPhone
    1
    亲,你这个肯定会慢,因为 database save 方法被频繁调用,而且是 block 的,如果你把 database save 异步就不会影响,或者定量写入,比如 1MB 写一次,也会降低影响。
    异常的问题可以通过异常处理模块补充。
    814084764
    814084764
    OP
    Oct 13, 2016
    2
    @bigboyq 异常的地方肯定有很多,除了下载模块的异常,还有其他模块的异常,如何去做补充?
    做一个全局的接收异常的方法?有些未捕获到的异常,又怎么处理呢?
    所以感觉异常这块的处理还是有点麻烦呢。。。束手无策的赶脚。
    要不就是改成写入到轻量级的文件中?
    Karblue
    Karblue
    Oct 13, 2016
    3
    不要写完就刷新硬盘。 IO 操作是很费时间的。存到缓存。然后再把缓存定时写出。
    例如:把文件数据暂时存在全局变量中。开单独的线程去写出全局变量的文件
    lrh3321
    lrh3321
    Oct 13, 2016
    4
    不支持 Linux ,我还是继续用 命令行吧
    lrh3321
    lrh3321
    Oct 13, 2016
    5
    回错了,要回另外个帖子的。
    ===============
    我觉得做个几 MB 的缓存,满了再写入磁盘。丢数据也就是丢缓存里这几 MB
    limhiaoing
    limhiaoing
    Oct 13, 2016 via iPhone
    6
    个人观点这个方法不可行。
    可以这么做,数据库记录已下载大小和 hash ,先写下载的数据到磁盘后记录下载进度和 hash 。
    limhiaoing
    limhiaoing
    Oct 13, 2016 via iPhone
    7
    这样既是异常终止在写完下载数据和记录下载进度之间也不要紧,根据上次记录的下载进度丢弃多余的数据,校验记录的 hash 即可。
    limhiaoing
    limhiaoing
    Oct 13, 2016 via iPhone
    8
    我估计迅雷的断点续传是用类似的方法,不过因为它是分块下载,所以 hash 应该也是分块计算的。
    ryd994
    ryd994
    Oct 13, 2016
    9
    其实简单办法就是检查当前文件大小
    直接从那个长度开始
    这也是 wget 的做法
    至于校验数据完整性……除非重新下一遍,否则 http 协议本身不含 checksum 做不到
    bigboyq
    bigboyq
    Oct 13, 2016 via iPhone
    10
    再起一个线程做 database.save 就好了,但是你又回来这里问数据库 update 慢怎么办。。。。。。
    icedx
    icedx
    Oct 13, 2016 via Android
    11
    别说我不友善啊
    你是不是 SS
    database.save(file.length());
    你这样能不慢么
    dlllcs
    dlllcs
    Oct 13, 2016
    12
    我觉得可以新建一个 Buffer ,大小差不多 32M 这样,每下载 32M 或者达到了 5 秒钟,就刷新进文件,这样比较好吧,这样 IO 比较少,而且丢数据也就丢最近几秒钟的数据
    limhiaoing
    limhiaoing
    Oct 13, 2016
    13
    单单靠文件长度来判断文件是否被篡改是不可靠的,文本被篡改不一定会导致文件长度改变。
    即使你这两句之间没有可能抛出异常,但是断电呢?
    file.write(buffer);
    database.save(file.length());
    所以,记录文件长度只能用于丢弃多余的数据,而不能用来校验文件是否被篡改。
    用 hash+长度来记录已下载的文件就不需要实时的去保存长度了。可以每下载 10MB 保存一次,这样如果进程异常结束,最多就是丢弃 10MB 的数据。
    814084764
    814084764
    OP
    Oct 14, 2016
    14
    @icedx 是有点傻。。哈哈
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1682 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 00:58 · PVG 08:58 · LAX 16:58 · JFK 19:58
    ♥ Do have faith in what you're doing.