一步一步带你起飞 ... ...

一、文件存储单位“字节”概念

1.1 存储单位

计算机是以字节(byte|B)为单位计算存储空间大小,如:1个数字和1个字母占用1个字节大小,而1个汉字是2个字节大小,常用单位有:KB\MB\GB\TB,再往上还有PB\EB\ZB\YB\BB。

对换关系,如下:

1024B = 1KB
1024KB = 1MB
1024MB = 1GB
1024GB = 1TB
1024TB = 1PB
...

1.2 文件举例

一个txt格式的文件:001.txt

  1. 内容:“abcd”,大小:“4字节”

  1. 内容:“abcd123”,大小:“7字节”

  1. 内容:“abcd123我”,大小:“9字节”

二、断点续传原理

文件在网络传输过程中时常会面对网络中断的情况,对于比较大的文件(花了30分钟上传了1G,还剩下2G没有完成)突然网断了,若重头开始上传的话前面花费30分钟时间上次的1G就完全浪费了(浪费时间、浪费流量),所以需要有一种机制可以从中断地方继续开始上传,这就是"断点续传"的概念。

2.1 断点存储

一般文件远程传输时不是直接存储为原文件格式,会存储为一个临时的格式,比如".temp",当文件传输完成后再修改为原文件格式名,比较常用的做法是之间在原文件名的后缀后面添加“.temp”后缀,如:“001.txt.temp”

对于只是续传来说临时文件的大小就可以认为是当前的断点,因为是往后追加方式存储,也有很多的下载上传工具(QQ旋风,迅雷,FTP客户端等)是支持多线程并发传输的,这个时候需要分配并记录多个断点。

比如:一个1024byte大小文件在远程接收时,以200byte为一个缓存块进行传输文件,也就是分隔成“0-200,201-401,402-602,603-803,804-1004,1005-1024”并行传输,传输效率提升非常可观。

2.2 文件续传读取

比如已经存储到508byte大小,那么需要从509byte开始上传,对于发送客户端需要从指定位置开始读取指定长度的文件字节码,发送给接收端。可以通过具体SDK包方法移动到文件某个字节位置开始读取指定大小,目前的开发语言库基本都支持此类的开发包。

2.3 文件续传存储

文件在网络中传输是通过字节码方式作为一个文件流。接收端收到的文件字节码流需要带有标志信息,如“337byte-797byte”,这样就可以把该字节流存储到临时文件中该指定位置,多次续传最终拼接成一个完整的文件。

2.4 文件校验-判断是否变化

在实际的上传下载操作中,存在文件发送过程中被变更的场景,所以在续传时需要明确知道文件是否变动,否则存储就会出现数据错误。没有变动继续续传,有变动重新开始传输。

本质是在文件传输端生成一个标志,发送给接收的端每次去比对是否一直一样。

三、http1.1协议支持策略

3.1 OSI模型定义

http1.1协议定义了断点续传文件内容的http请求头参数:Range\Content-Range。Range参数是本地发往服务器的http头参数。Content-Range是远程服务器发往本地http头参数。

3.2 Range\Cotent-Range

range: (unit=first byte pos)-[last byte pos] : 指定第一个字节位置和最后一个字节位置。

例子说明:

range: bytes=0-1300

表示第0-1300字节范围的内容发往远程服务器。

range: bytes=1301-23041

表示第1201-23041字节范围的内容发往远程服务器。

Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth]

例子说明

content-Range: bytes 0-797/1024000

表示0-797字节范围内容从服务器响应到客户端,1024000是文件总大小。

完成http响应后,http状态码返回:206 表示使用断掉续传方式,而一般200表示不使用断掉续传方式。

3.3 Last-Modified\If-Modified-Since

利用HTTP协议头Last-Modified\If-Modified-Since参数存储文件最后修改日期,每次通信文件要判断与上一次文件最后修改日期是否相同,如果不同就从0开始重新接收文件,相同则继续。Last-Modified 是由服务器往客户端发送的 HTTP 头,而If-Modified-Since 则是由客户端往服务器发送的头。

例如:

Last-Modified: Fri, 22 Feb 2013 03:45:02 GMT

服务器端返回客户端HTTP头信息。

If-Modified-Since: Fri, 22 Feb 2013 03:45:02 GMT

客户端通过 If-Modified-Since HTTP头将上一次服务器端发过来的 Last-Modified 时间戳发送回服务器端进行比较验证。

3.4 Etag\If-Range

Etage也是一种校验的策略,服务器发送给客户端的HTTP头带上Etage参数,客户端发送给服务器通过If-Range把上一次的Etage参数返回给服务器端验证,如果不一样就返回完整从0字节开始的内容,206状态码;若果一样就继续返回要求的自己内容,200状态码。

Etage机制是弥补一些Last-Modified无法支持的场景,如服务无法识别文件最后修改时间,又或者在秒以下的时间内进行修改N次。HTTP/1.1标准并没有规定Etag的内容是什么或者说要怎么实现,唯一规定的是Etag必须用""括起来,所以Etage是由服务器端决定按什么策略生产,不同公司不同见解了。

除了If-Range外还有If-Match\If-None-Match两种参数,用法同If-Range一样,如下:

服务器端发送 客户端发送
Etage: "112233" If-Range: "112233"
If-Match: "112233"
If-None-Match: "112233"

3.4 http断掉续传测试验证

举例: --Range 0-1000

$ curl.exe -i --Range 0-1000 http://www.baidu.com/img/bdlogo.gif% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100  1001  100  1001    0     0  21760      0 --:--:-- --:--:-- --:--:-- 21760HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Cache-Control: max-age=315360000
Connection: Keep-Alive
Content-Length: 1001
Content-Range: bytes 0-1000/1575
Content-Type: image/gif
Date: Fri, 07 Jun 2019 06:50:06 GMT
Etag: "627-4d648041f6b80"
Expires: Mon, 04 Jun 2029 06:50:06 GMT
Last-Modified: Fri, 22 Feb 2013 03:45:02 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: Apache
Set-Cookie: BAIDUID=46BF24BA4F3649CE9214E2DA266439B1:FG=1; expires=Sat, 06-Jun-20 06:50:06 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1GIF89a▒▒`g▒▒1.▒▒▒▒▒▒▒▒jg▒▒▒▒▒▒▒▒▒▒▒▒▒4<▒EL▒)2▒▒▒▒▒!▒,▒▒▒▒I▒▒8▒ͻ▒`(▒di▒h▒▒l▒p,▒tm▒x▒▒|▒▒▒▒pH,▒Ȥr▒l:▒ШtJ▒Z▒جv▒▒z▒▒xL.▒▒▒z▒n▒▒▒|N▒▒▒▒▒~▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒     ▒▒▒▒▒▒}▒▒
▒z▒▒▒▒▒▒ã               ▒
▒▒▒▒▒o▒▒▒▒▒▒▒m  آ▒▒s▒▒▒▒▒▒▒▒▒▒▒@▒▒h▒▒▒▒w▒&$#A*N▒▒▒5!Z3▒▒▒$▒g▒▒a▒H▒IF#▒▒▒H▒▒▒▒▒▒▒a̙6▒▒▒▒▒xT%ƠV▒+xB▒P▒P▒x▒▒▒*▒▒Sp[Xb▒0▒`▒<▒b-ѴP▒▒BK▒▒}▒^▒▒▒▒▒.P▒
]       1▒u▒▒▒.l▒QX▒`▒▒w▒▒@▒▒▒▒▒9▒▒Ӣ(0▒E▒▒.Lp▒d▒▒lz4▒Ҩ▒▒&▒▒ih▒Нݐs[▒N}▒▒▒[▒▒u▒'▒▒▒▒▒▒b▒▒~▒C▒ݻ[▒▒];▒▒CX!t▒▒h▒▒▒▒ئ
:▒▒7▒|
_▒=▒`▒▒1▒▒h▒(▒X"xm▒_|▒▒▒(@▒▒7~p1▒▒nV▒*▒▒!▒E▒g▒▒▒M8A▒,Bx ▒;8e▒▒]y%▒▒▒▒":)▒u▒▒▒▒I▒f▒Q▒K
▒▒▒▒ ▒▒▒nn▒i▒▒jNVȁ▒u▒▒▒}▒▒▒▒:▒▒vSr▒▒▒p▒▒f▒;[▒ً▒"V:i▒▒Z
h▒▒ok*h_▒Y▒=▒▒▒(K▒&▒
Tg▒     ▒▒ˣ▒         ▒▒▒*hL2▒▒▒t▒Z▒V[▒▒z֚▒w▒▒v▒l▒▒▒▒▒3J▒▒6▒▒▒▒▒▒▒Kh▒▒^▒n[A▒&▒8\▒▒▒u▒d4@▒▒މ▒▒▒▒me*[▒▒(▒▒▒▒/}jn`▒▒▒jLI▒`▒▒▒▒·▒▒▒▒▒Ɨ▒B▒v▒▒▒"? ▒<T

说明:

获取0-1000字节的内容,服务器返回状态码206,标识成功。

Etag: "627-4d648041f6b80"
Content-Length: 1001
Content-Range: bytes 0-1000/1575

举例: --Range 1001-1575 --header 'If-Range: "627-4d648041f6b80"'

$ curl.exe -i --Range 1001-1575 --header 'If-Range: "627-4d648041f6b80"' http://www.baidu.com/img/bdlogo.gif% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100   574  100   574    0     0  12478      0 --:--:-- --:--:-- --:--:-- 12478HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Cache-Control: max-age=315360000
Connection: Keep-Alive
Content-Length: 574
Content-Range: bytes 1001-1574/1575
Content-Type: image/gif
Date: Fri, 07 Jun 2019 06:54:44 GMT
Etag: "627-4d648041f6b80"
Expires: Mon, 04 Jun 2029 06:54:44 GMT
Last-Modified: Fri, 22 Feb 2013 03:45:02 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: Apache
Set-Cookie: BAIDUID=0E38B0989374B9F142B24462CD98ADA4:FG=1; expires=Sat, 06-Jun-20 06:54:44 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1▒▒01c<▒▒mV▒▒[▒▒u▒▒▒-C▒▒▒▒s]▒▒M▒\▒u|▒▒w▒▒▒▒▒▒x▒T▒K]▒
ZK▒?▒▒g▒▒▒৳▒▒[M▒ZH_p▒▒c▒▒F▒y▒7▒▒▒I@▒▒▒~h▒▒▒▒]=▒▒▒&▒▒cU▒=▒▒▒GJ▒}▒k▒i▒W=w▒΅-▒+▒H`▒H▒▒()'(▒j▒▒▒i▒▒3&▒9▒8▒3Ą▒▒▒uJ▒&6▒J4:c^▒^tb▒6ܚ▒▒▒▒▒j▒▒.▒9O▒▒ac▒ц▒▒3=▒Ս▒h̞▒G▒▒4+da▒▒▒▒▒J▒J▒J֘▒▒:oD ▒▒▒D
( ▒▒▒▒UƼt▒[▒▒▒▒j▒▒?NiBc-▒▒^▒▒▒▒SK▒▒s▒▒0▒I▒b▒▒L▒2▒▒▒f:▒Ќ▒4▒I▒jZ▒▒̦6▒▒▒nz▒▒▒8▒I▒r▒▒▒L▒:▒▒▒v▒▒▒▒▒<▒I▒z▒ ;

说明:

获取1001-1575字节码内容,返回码206标识成功。两次请求的Content-Length字段值相加(1001+574=1575)正好等于总长度。

Content-Range: bytes 1001-1574/1575
Content-Length: 574
Etag: "627-4d648041f6b80"

举例Etag校验失败: --Range 1001-1575 --header 'If-Range: "627-4d648041f6b81"'

$ curl.exe -i --Range 1001-1575 --header 'If-Range: "627-4d648041f6b81"' http://www.baidu.com/img/bdlogo.gif% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100  1575  100  1575    0     0  25403      0 --:--:-- --:--:-- --:--:-- 25403HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=315360000
Connection: Keep-Alive
Content-Length: 1575
Content-Type: image/gif
Date: Fri, 07 Jun 2019 07:07:53 GMT
Etag: "627-4d648041f6b80"
Expires: Mon, 04 Jun 2029 07:07:53 GMT
Last-Modified: Fri, 22 Feb 2013 03:45:02 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: Apache
Set-Cookie: BAIDUID=77C9D6AD24F8A5F39F1B35D7D351D05C:FG=1; expires=Sat, 06-Jun-20 07:07:53 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1GIF89a▒▒`g▒▒1.▒▒▒▒▒▒▒▒jg▒▒▒▒▒▒▒▒▒▒▒▒▒4<▒EL▒)2▒▒▒▒▒!▒,▒▒▒▒I▒▒8▒ͻ▒`(▒di▒h▒▒l▒p,▒tm▒x▒▒|▒▒▒▒pH,▒Ȥr▒l:▒ШtJ▒Z▒جv▒▒z▒▒xL.▒▒▒z▒n▒▒▒|N▒▒▒▒▒~▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒     ▒▒▒▒▒▒}▒▒
▒z▒▒▒▒▒▒ã               ▒
▒▒▒▒▒o▒▒▒▒▒▒▒m  آ▒▒s▒▒▒▒▒▒▒▒▒▒▒@▒▒h▒▒▒▒w▒&$#A*N▒▒▒5!Z3▒▒▒$▒g▒▒a▒H▒IF#▒▒▒H▒▒▒▒▒▒▒a̙6▒▒▒▒▒xT%ƠV▒+xB▒P▒P▒x▒▒▒*▒▒Sp[Xb▒0▒`▒<▒b-ѴP▒▒BK▒▒}▒^▒▒▒▒▒.P▒
]       1▒u▒▒▒.l▒QX▒`▒▒w▒▒@▒▒▒▒▒9▒▒Ӣ(0▒E▒▒.Lp▒d▒▒lz4▒Ҩ▒▒&▒▒ih▒Нݐs[▒N}▒▒▒[▒▒u▒'▒▒▒▒▒▒b▒▒~▒C▒ݻ[▒▒];▒▒CX!t▒▒h▒▒▒▒ئ
:▒▒7▒|
_▒=▒`▒▒1▒▒h▒(▒X"xm▒_|▒▒▒(@▒▒7~p1▒▒nV▒*▒▒!▒E▒g▒▒▒M8A▒,Bx ▒;8e▒▒]y%▒▒▒▒":)▒u▒▒▒▒I▒f▒Q▒K
▒▒▒▒ ▒▒▒nn▒i▒▒jNVȁ▒u▒▒▒}▒▒▒▒:▒▒vSr▒▒▒p▒▒f▒;[▒ً▒"V:i▒▒Z
h▒▒ok*h_▒Y▒=▒▒▒(K▒&▒
Tg▒     ▒▒ˣȆ▒01c<▒▒mV▒▒[▒▒u▒▒▒-C▒▒▒▒s]▒▒M▒\▒u|▒▒w▒▒▒▒▒▒x▒T▒K]▒▒▒Kh▒▒^▒n[A▒&▒8\▒▒▒u▒d4@▒▒މ▒▒▒▒me*[▒▒(▒▒▒▒/}jn`▒▒▒jLI▒`▒▒▒▒·▒▒▒▒▒Ɨ▒B▒v▒▒▒"? ▒<T
ZK▒?▒▒g▒▒▒৳▒▒[M▒ZH_p▒▒c▒▒F▒y▒7▒▒▒I@▒▒▒~h▒▒▒▒]=▒▒▒&▒▒cU▒=▒▒▒GJ▒}▒k▒i▒W=w▒΅-▒+▒H`▒H▒▒()'▒(▒j▒▒▒i▒▒3&▒9▒8▒3Ą▒▒▒uJ▒&6▒J4:c^▒^tb▒6ܚ▒▒▒▒▒j▒▒.▒9O▒▒ac▒ц▒▒3=▒Ս▒h̞▒G▒▒4+da▒▒▒▒▒J▒J▒J֘▒▒:oD ▒▒▒D
( ▒▒▒▒UƼt▒[▒▒▒▒j▒▒?NiBc-▒▒^▒▒▒▒SK▒▒s▒▒0▒I▒b▒▒L▒2▒▒▒f:▒Ќ▒4▒I▒jZ▒▒̦6▒▒▒nz▒▒▒8▒I▒r▒▒▒L▒:▒▒▒v▒▒▒▒▒<▒I▒z▒ ;

说明:

通过If-Range与Etag比较发现值不同,此时没有Content-Range头参数信息,服务器则把完整的文件内容全部传给客户端。

If-Range: "627-4d648041f6b81"

Etag: "627-4d648041f6b80"

比较着看你会发现同一般非断点续传的HTTP请求返回一样,如下:

$ curl.exe -i http://www.baidu.com/img/bdlogo.gif% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100  1575  100  1575    0     0  34239      0 --:--:-- --:--:-- --:--:-- 34239HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=315360000
Connection: Keep-Alive
Content-Length: 1575
Content-Type: image/gif
Date: Fri, 07 Jun 2019 07:11:20 GMT
Etag: "627-4d648041f6b80"
Expires: Mon, 04 Jun 2029 07:11:20 GMT
Last-Modified: Fri, 22 Feb 2013 03:45:02 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: Apache
Set-Cookie: BAIDUID=1F8BCA97A9EB1C3123305CC96E3AFD12:FG=1; expires=Sat, 06-Jun-20 07:11:20 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1GIF89a▒▒`g▒▒1.▒▒▒▒▒▒▒▒jg▒▒▒▒▒▒▒▒▒▒▒▒▒4<▒EL▒)2▒▒▒▒▒!▒,▒▒▒▒I▒▒8▒ͻ▒`(▒di▒h▒▒l▒p,▒tm▒x▒▒|▒▒▒▒pH,▒Ȥr▒l:▒ШtJ▒Z▒جv▒▒z▒▒xL.▒▒▒z▒n▒▒▒|N▒▒▒▒▒~▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒     ▒▒▒▒▒▒}▒▒
▒z▒▒▒▒▒▒ã               ▒
▒▒▒▒▒o▒▒▒▒▒▒▒m  آ▒▒s▒▒▒▒▒▒▒▒▒▒▒@▒▒h▒▒▒▒w▒&$#A*N▒▒▒5!Z3▒▒▒$▒g▒▒a▒H▒IF#▒▒▒H▒▒▒▒▒▒▒a̙6▒▒▒▒▒xT%ƠV▒+xB▒P▒P▒x▒▒▒*▒▒Sp[Xb▒0▒`▒<▒b-ѴP▒▒BK▒▒}▒^▒▒▒▒▒.P▒
]       1▒u▒▒▒.l▒QX▒`▒▒w▒▒@▒▒▒▒▒9▒▒Ӣ(0▒E▒▒.Lp▒d▒▒lz4▒Ҩ▒▒&▒▒ih▒Нݐs[▒N}▒▒▒[▒▒u▒'▒▒▒▒▒▒b▒▒~▒C▒ݻ[▒▒];▒▒CX!t▒▒h▒▒▒▒ئ
:▒▒7▒|
_▒=▒`▒▒1▒▒h▒(▒X"xm▒_|▒▒▒(@▒▒7~p1▒▒nV▒*▒▒!▒E▒g▒▒▒M8A▒,Bx ▒;8e▒▒]y%▒▒▒▒":)▒u▒▒▒▒I▒f▒Q▒K
▒▒▒▒ ▒▒▒nn▒i▒▒jNVȁ▒u▒▒▒}▒▒▒▒:▒▒vSr▒▒▒p▒▒f▒;[▒ً▒"V:i▒▒Z
h▒▒ok*h_▒Y▒=▒▒▒(K▒&▒
Tg▒     ▒▒ˣȆ▒01c<▒▒mV▒▒[▒▒u▒▒▒-C▒▒▒▒s]▒▒M▒\▒u|▒▒w▒▒▒▒▒▒x▒T▒K]▒▒▒Kh▒▒^▒n[A▒&▒8\▒▒▒u▒d4@▒▒މ▒▒▒▒me*[▒▒(▒▒▒▒/}jn`▒▒▒jLI▒`▒▒▒▒·▒▒▒▒▒Ɨ▒B▒v▒▒▒"? ▒<T
ZK▒?▒▒g▒▒▒৳▒▒[M▒ZH_p▒▒c▒▒F▒y▒7▒▒▒I@▒▒▒~h▒▒▒▒]=▒▒▒&▒▒cU▒=▒▒▒GJ▒}▒k▒i▒W=w▒΅-▒+▒H`▒H▒▒()'▒(▒j▒▒▒i▒▒3&▒9▒8▒3Ą▒▒▒uJ▒&6▒J4:c^▒^tb▒6ܚ▒▒▒▒▒j▒▒.▒9O▒▒ac▒ц▒▒3=▒Ս▒h̞▒G▒▒4+da▒▒▒▒▒J▒J▒J֘▒▒:oD ▒▒▒D
( ▒▒▒▒UƼt▒[▒▒▒▒j▒▒?NiBc-▒▒^▒▒▒▒SK▒▒s▒▒0▒I▒b▒▒L▒2▒▒▒f:▒Ќ▒4▒I▒jZ▒▒̦6▒▒▒nz▒▒▒8▒I▒r▒▒▒L▒:▒▒▒v▒▒▒▒▒<▒I▒z▒ ;

If-Match举例(If-None-Match完全一样),如下:

$ curl.exe -i --Range 1001-1575 --header 'If-Match: "627-4d648041f6b80"' http://www.baidu.com/img/bdlogo.gif% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100   574  100   574    0     0  12212      0 --:--:-- --:--:-- --:--:-- 12212HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Cache-Control: max-age=315360000
Connection: Keep-Alive
Content-Length: 574
Content-Range: bytes 1001-1574/1575
Content-Type: image/gif
Date: Fri, 07 Jun 2019 10:21:48 GMT
Etag: "627-4d648041f6b80"
Expires: Mon, 04 Jun 2029 10:21:48 GMT
Last-Modified: Fri, 22 Feb 2013 03:45:02 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: Apache
Set-Cookie: BAIDUID=A87AAF66C9055950B0240738025FD7CF:FG=1; expires=Sat, 06-Jun-20 10:21:48 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1▒▒01c<▒▒mV▒▒[▒▒u▒▒▒-C▒▒▒▒s]▒▒M▒\▒u|▒▒w▒▒▒▒▒▒x▒T▒K]▒
ZK▒?▒▒g▒▒▒৳▒▒[M▒ZH_p▒▒c▒▒F▒y▒7▒▒▒I@▒▒▒~h▒▒▒▒]=▒▒▒&▒▒cU▒=▒▒▒GJ▒}▒k▒i▒W=w▒΅-▒+▒H`▒H▒▒()'(▒j▒▒▒i▒▒3&▒9▒8▒3Ą▒▒▒uJ▒&6▒J4:c^▒^tb▒6ܚ▒▒▒▒▒j▒▒.▒9O▒▒ac▒ц▒▒3=▒Ս▒h̞▒G▒▒4+da▒▒▒▒▒J▒J▒J֘▒▒:oD ▒▒▒D
( ▒▒▒▒UƼt▒[▒▒▒▒j▒▒?NiBc-▒▒^▒▒▒▒SK▒▒s▒▒0▒I▒b▒▒L▒2▒▒▒f:▒Ќ▒4▒I▒jZ▒▒̦6▒▒▒nz▒▒▒8▒I▒r▒▒▒L▒:▒▒▒v▒▒▒▒▒<▒I▒z▒ ;

四、java文件读写

常用的字节或字符流操作文件默认都是从文件开始位置写入(从0开始),但是我们需要的是从指定位置开始写入并控制写入多少。

4.1 例子

//File content: “1234abc我”
File file = new File("F:\\tmp\\001.txt");
System.out.println(file.length());
//输出:9String insert = "1tt1";
byte[] bytes = insert.getBytes();
long currentLength = file.length();
System.out.println(bytes.length);
//输出:4RandomAccessFile raf = new RandomAccessFile(file,"rw");
raf.seek(currentLength+5);//写入位置指定到第15字节处开始
raf.write(bytes,0,bytes.length);
System.out.println(file.length());
//输出:18
//文件内容:“1234abc我     1tt1”insert+=",";
bytes = insert.getBytes();
raf.seek(currentLength);//写入位置指定到第10字节处开始
raf.write(bytes,0,bytes.length);
System.out.println(file.length());
//输出:18
//文件内容:“1234abc我1tt1,1tt1”

4.2 说明

通过 Java RandomAccessFile 类的 .seek(..) 方法可以控制文件写入位置。例子中第二次写入内容“1tt1,”是从第10个字节处写入内容。

4.3 Java .seek(..) 方法源码

注意看方法的注释:在写入内容前改变file-pointer offset不会影响文件的大小。

/*** Sets the file-pointer offset, measured from the beginning of this* file, at which the next read or write occurs.  The offset may be* set beyond the end of the file. Setting the offset beyond the end* of the file does not change the file length.  The file length will* change only by writing after the offset has been set beyond the end* of the file.** @param      pos   the offset position, measured in bytes from the*                   beginning of the file, at which to set the file*                   pointer.* @exception  IOException  if {@code pos} is less than*                          {@code 0} or if an I/O error occurs.*/
public void seek(long pos) throws IOException {if (pos < 0) {throw new IOException("Negative seek offset");} else {seek0(pos);}
}private native void seek0(long pos) throws IOException;

五、HTTP文件断点续传时序图

推荐链接

作者:Owen Jia,他的博客:Owen Blog

推荐他的公众号:冬天就要吃胖点,有很多技术文章

转载于:https://my.oschina.net/timestorm/blog/3059516

带你深度解析断点续传原理并案例Http1.1协议相关推荐

  1. Python大数据综合应用 :零基础入门机器学习、深度学习算法原理与案例

    机器学习.深度学习算法原理与案例实现暨Python大数据综合应用高级研修班 一.课程简介 课程强调动手操作:内容以代码落地为主,以理论讲解为根,以公式推导为辅.共4天8节,讲解机器学习和深度学习的模型 ...

  2. 【进阶3-5期】深度解析 new 原理及模拟实现

    定义 new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例. --(来自于MDN) 举个栗子 function Car(color) {this.color = color; ...

  3. 【进阶3-4期】深度解析bind原理、使用场景及模拟实现

    bind() bind() 方法会创建一个新函数,当这个新函数被调用时,它的 this 值是传递给 bind() 的第一个参数,传入bind方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺 ...

  4. 一文带你深度解析腾讯云直播答题方案

    欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:腾讯视频云 进入2018年最火的新鲜事物无疑就是"直播答题"了,动辄上百万的奖金更是吸引了大量用户的参与.一场直播动辄 ...

  5. 带你深度解析Maven

    一.What`s Maven? Maven是基于项目对象模型(POM project object model),可以通过一小段描述信息(配置)来管理项目的构建,报告和文档的软件项目管理工具,简单的说 ...

  6. 图文并茂——从Kubernetes的诞生背景到什么是Kubernetes, 带你深度解析Kubernetes

    在云原生技术发展的浪潮之中,Kubernetes作为容器编排领域的事实标准和云原生领域的关键项目,其诞生与完善有着对应的技术历史背景,了解这个过程,对于系统的理解Kubernetes的核心思想.架构设 ...

  7. 怎么做 空间杜宾模型_企业营销怎么做?深度解析STP模型及案例,一步成高手...

    STP模型是整个营销的构建基础,包括了市场细分(Segmenting).目标市场(Targeting)和产品定位(Positioning) 三部分内容 现在企业比拼的是垂直度.做的是差异化.收口的是粉 ...

  8. K8s项目实战笔记 图文并茂带你深度解析Kubernetes

    一.前言 Kubernetes(简称K8S)是开源的容器集群管理系统,可以实现容器集群的自动化部署.自动扩缩容.维护等功能.它既是一款容器编排工具,也是全新的基于容器技术的分布式架构领先方案.在Doc ...

  9. 带你深度解析虚幻引擎4的照明和阴影知识

    照明是渲染的重要组成部分.有静态光和动态光,它们往往很重并且需要大量计算.今天就让赞奇云工作站带领小伙伴们来学习一下虚幻引擎4中的光照和阴影的知识. 静态照明 静态光在编辑器中预先计算并保存在光照贴图 ...

  10. 阿里P8架构师力荐K8s项目实战笔记 图文并茂带你深度解析Kubernetes

    一.前言 Kubernetes(简称K8S)是开源的容器集群管理系统,可以实现容器集群的自动化部署.自动扩缩容.维护等功能.它既是一款容器编排工具,也是全新的基于容器技术的分布式架构领先方案.在Doc ...

最新文章

  1. SQL 2014新特性- Delayed durability
  2. Leetcode 141. Linked List CycleJAVA语言
  3. (课程学习笔记)Python基础学习
  4. oracle 取mac地址,java执行命令,得到Mac地址
  5. UI标签库专题二:JEECG智能开发平台Column(列) 子标签
  6. Android Studio(7)---查找例子
  7. Oracle修改实例名SID
  8. 《Linux命令行与shell脚本编程大全》第十二章 使用结构化命令
  9. UVa 548 Tree(中序遍历+后序遍历)
  10. C#综合揭秘——细说多线程(下)(转载)
  11. java xml解析 jdom_Java语言中XML的JDom解析方式
  12. 东北工学院 计算机 姚岚,东北的大学最强十校,工科是真强,2所211大学无缘前十...
  13. 华硕电脑重装系统后fn组合键部分屏幕无显示
  14. 容联云通讯php短信接口,开发中使用 【容联 云通信】获取短信验证码的 Javascript 接口...
  15. 冯诺依曼最伟大的发现?----元胞自动机
  16. kermit config files
  17. java class的方法_Java Class类常用方法描述
  18. 逆天了!看大二学生做的超写实CG卷尾猴!
  19. win10怎么更改账户名称_如何自定义WIN10登陆界面的用户名?
  20. 多重检验的p值校正:FWER和FDR

热门文章

  1. sql语句左连接时的ON AND用法
  2. 1分钟彻底搞懂关于nginx的proxy_pass
  3. Zabbix调优不完全指南
  4. 数据分析课堂笔记Day10(20221123)
  5. 使用Go语言开发生成阿里云ECS监控报表,定时自动发送邮件给指定人员
  6. 函数发生器与计算机电路,第29讲 信号发生器与变换电路
  7. 有什么好的搜图软件推荐吗?
  8. chm打开,显示“已取消到该网站的导航”
  9. Android - 城市/单项/国家区号选择器基础使用 及 使用国际区号json文件
  10. Windows Mobile Pocket PC的文件系统