很简单的Java断点续传实现原理
原理解析
在开发当中,“断点续传”这种功能很实用和常见,听上去也是比较有“逼格”的感觉。所以通常我们都有兴趣去研究研究这种功能是如何实现的?
以Java来说,网络上也能找到不少关于实现类似功能的资料。但是呢,大多数都是举个Demo然后贴出源码,真正对其实现原理有详细的说明很少。
于是我们在最初接触的时候,很可能就是直接Crtl+C/V代码,然后捣鼓捣鼓,然而最终也能把效果弄出来。但初学时这样做其实很显然是有好有坏的。
好处在于,源码很多,解释很少;如果我们肯下功夫,针对于别人贴出的代码里那些自己不明白的东西去查资料,去钻研。最终多半会收获颇丰。
坏处也很明显:作为初学者,面对一大堆的源码,感觉好多东西都很陌生,就很容易望而生畏。即使最终大致了解了用法,但也不一定明白实现原理。
我们今天就一起从最基本的角度切入,来看看所谓的“断点续传”这个东西是不是真的如此“高逼格”。
其实在接触一件新的“事物”的时候,将它拟化成一些我们本身比较熟悉的事物,来参照和对比着学习。通常会事半功倍。
如果我们刚接触“断点续传”这个概念,肯定很难说清楚个一二三。那么,“玩游戏”我们肯定不会陌生。
OK,那就假设我们现在有一款“通关制的RPG游戏”。想想我们在玩这类游戏时通常会怎么做?
很明显,第一天我们浴血奋战,大杀四方,假设终于来到了第四关。虽然激战正酣,但一看墙上的时钟,已经凌晨12点,该睡觉了。
这个时候就很尴尬了,为了能够在下一次玩的时候,顺利接轨上我们本次游戏的进度,我们应该怎么办呢?
很简单,我们不关掉游戏,直接去睡觉,第二天再接着玩呗。这样是可以,但似乎总觉着有哪里让人不爽。
那么,这个时候,如果这个游戏有一个功能叫做“存档”,就很关键了。我们直接选择存档,输入存档名“第四关”,然后就可以关闭游戏了。
等到下次进行游戏时,我们直接找到“第四关”这个存档,然后进行读档,就可以接着进行游戏了。
这个时候,所谓的“断点续传”就很好理解了。我们顺着我们之前“玩游戏”的思路来理一下:
假设,现在有一个文件需要我们进行下载,当我们下载了一部分的时候,出现情况了,比如:电脑死机、没电、网络中断等等。
其实这就好比我们之前玩游戏玩着玩着,突然12点需要去睡觉休息了是一个道理。OK,那么这个时候的情况是:
•如果游戏不能存档,那么则意味着我们下次游戏的时候,这次已经通过的4关的进度将会丢失,无法接档。
•对应的,如果“下载”的行为无法记录本次下载的一个进度。那么,当我们再次下载这个文件也就只能从头来过。
话到这里,其实我们已经发现了,对于我们以上所说的行为,关键就在于一个字“续”!
而我们要实现让一种断开的行为“续”起来的目的,关键就在于要有“介质”能够记录和读取行为出现”中断”的这个节点的信息。
转化到编程世界
实际上这就是“断点续传”最最基础的原理,用大白话说就是:我们要在下载行为出现中断的时候,记录下中断的位置信息,然后在下次行为中读取。
有了这个位置信息之后,想想我们该怎么做。是的,很简单,在新的下载行为开始的时候,直接从记录的这个位置开始下载内容,而不再从头开始。
好吧,我们用大白话掰扯了这么久的原理,开始觉得无聊了。那么我们现在最后总结一下,然后就来看看我们应该怎么把原理转换到编程世界中去。
•当“上传(下载)的行为”出现中断,我们需要记录本次上传(下载)的位置(position)。
•当“续”这一行为开始,我们直接跳转到postion处继续上传(下载)的行为。
显然问题的关键就在于所谓的“position”,以我们举的“通关游戏来说”,可以用“第几关”来作为这个position的单位。
那么转换到所谓的“断点续传”,我们该使用什么来衡量“position”呢?很显然,回归二进制,因为这里的本质无非就是文件的读写。
那么剩下的工作就很简单了,先是记录position,这似乎都没什么值得说的,因为只是数据的持久化而已(内存,文件,数据库),我们有很多方式。
另一个关键在于当“续传”的行为开始,我们需要需要从上次记录的position位置开始读写操作,所以我们需要一个类似于“指针”功能的东西。
我们当然也可以自己想办法去实现这样一个“指针”,但高兴地是,Java已经为我们提供了这样的一个类,那就是RandomAccessFile。
这个类的功能从名字就很直观的体现了,能够随机的去访问文件。我们看一下API文档中对该类的说明: