首先传输一个文件片段所需的信息:
1.该文件的目录(主要为了获取文件)
2.该片段相对于文件的偏移量
3.该片段的长度
传递本身基于上次的二进制文件传输以及做好了二进制的转换可以实现,但需要考虑片段传输时传输出错的情况,即断点续传。
为了做到断点续传需要将没有接收到的部分发送给接收端,用于继续获取文件。
总共有8个变量:
orgOffset:传送前的偏移量
orgLength:长度
rcvOffset:接收文件片段对应偏移量
rcvLength:长度
传送后,被切分成左右两段未传输的片段
leftOffset:左侧偏移量
leftLength:长度
rightOffset:右侧偏移量
rightLength:长度
思想是将每一个片段A先由一个list记录起来,当接收到文件片段时,原先的文件就被分割成左B、右C两段,接着这两段B、C可以看做是两个新的A,接着这段操作。
传输结束的标志:存储list为空,即文件都传输完毕。
当list不为空,但不继续传输,说明传输出错了,而list中的信息就是缺少的文件片段,下次续传取list中的传输即可。
实际推导:
假设有一个文件,长度为15(个单位),下面有三次发送的片段信息:
1、3:4
2、10:2
3、7:3
需要根据上述三段信息,能计算出还有哪些片段尚未发送!
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
在未发送前,本文件尚未接收的片段信息是:
0:15
第1次:
offset:3
length:4
_ _ _ x x x x _ _ _ _ _ _ _ _
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
此时,尚未发送的片段信息是:
0:3
7:8
首先,原来的0:15必然被删除;
0:3的获取过程:
先定义变量如下:
0:15(orgOffset:orgLength)
3:4(rcvOffset:rcvLength)
应该由当前接收到的片段,将org片段分割成两个部分:
leftOffset:leftLength
rightOffset:rightLength
leftOffset = orgOffset; 0
leftLength = rcvOffset - orgOffset; 3
rightOffset = rcvOffset + rcvLength; 7
rightLength = orgOffset + orgLength - rightOffset; 8
(这里左右就将被存到list中)
第2次:
offset:10
length:2
_ _ _ x x x x _ _ _ y y _ _ _
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
此时,尚未发送的片段信息是:
0:3
7:3
12:3
orgOffset:7
orgLength:8
rcvOffset:10
rcvLength:2
leftOffset = orgOffset; 7
leftLength = rcvOffset - orgOffset 3
rightOffset = rcvOffset + rcvLength 12
rightLength = orgOffset + orgLength - rightOffset 3
第3次:
offset:7
length:3
_ _ _ x x x x z z z y y _ _ _
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
此时,尚未发送的片段信息是:
0:3
12:3
可以看到总体流程:
接收片段,找到该片段位于哪一段未接收的文件片段中,更改该片段的信息,再将更改后的加入到list中存储。
固需要一个查找片段的函数:
private int findSection(OffsetLength currentSection) {
for (int index = 0; index < this.sectionList.size(); index++) {
OffsetLength section = this.sectionList.get(index);
if (section.getOffset() + section.getLength() > currentSection.getOffset()) {
return index;
}
}
return -1;
}
这一段表示基于一段收到的文件片段,在list中寻找,当某一段的偏移量+长度(即他在文件中所占的截止位置)包括了接收片段的偏移量(起始位置),说明该段就找到了。
找到后进行操作如下:
public void receiveFileSection(FileSectionInfo fileSectionInfo) throws FileSectionFailureException {
OffsetLength currentSection = new OffsetLength(
fileSectionInfo.getOffset(), fileSectionInfo.getLength());
int index = findSection(currentSection);
if (index == -1) {
throw new FileSectionFailureException("文件片段异常:" + fileSectionInfo);
}
OffsetLength orgOffsetLength = this.sectionList.get(index);
long orgOffset = orgOffsetLength.getOffset();
long orgLength = orgOffsetLength.getLength();
long rcvOffset = currentSection.getOffset();
long rcvLength = currentSection.getLength();
long leftOffset = orgOffset;
long leftLength = rcvOffset - orgOffset;
long rightOffset = rcvOffset + rcvLength;
long rightLength = orgOffset + orgLength - rightOffset;
this.sectionList.remove(index);
if (rightLength > 0) {
this.sectionList.add(index, new OffsetLength(rightOffset, rightLength));
}
if (leftLength > 0) {
this.sectionList.add(index, new OffsetLength(leftOffset, leftLength));
}
}
找到后就进行分割操作,注意分割完成后需要删除原先list存储的片段,将该片段由右片段+左片段替换(因为用的是链表,注意先放入右片段,这样左在加入时会将右片段挤到右侧)。