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

Owen Jia 2019年06月19日 224次浏览

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

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

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字节”

abcd

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

abcd123

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

abcd123我

二、断点续传原理

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

bytes

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包方法移动到文件某个字节位置开始读取指定大小,目前的开发语言库基本都支持此类的开发包。

middle-size

2.3 文件续传存储

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

litte-splite

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

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

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

三、http1.1协议支持策略

3.1 OSI模型定义

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  Current
                                 Dload  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=1

GIF89a▒▒`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  Current
                                 Dload  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  Current
                                 Dload  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=1

GIF89a▒▒`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  Current
                                 Dload  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=1

GIF89a▒▒`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  Current
                                 Dload  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());
//输出:9

String insert = "1tt1";
byte[] bytes = insert.getBytes();
long currentLength = file.length();
System.out.println(bytes.length);
//输出:4

RandomAccessFile 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,里面有更多技术文章。