RandomAccessFile短点续传
1. 什么是短点续传?
# FTP(文件传输协议的简称)(File Transfer Protocol、 FTP)客户端软件断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载。用户可以节省时间,提高速度。
2. RandomAccessFile类
2.1 读写的函数
package com. liu. learn ;
import org. junit. Test ;
import java. io. File ;
import java. io. RandomAccessFile ;
import java. nio. charset. StandardCharsets ;
public class RandomAccessFileTest {
@Test
public void read ( ) throws Exception {
File file = new File ( "D:/E_DISK/IDEAJavaCode/BreakingPointFile/a.txt" ) ;
RandomAccessFile randomAccessFile = new RandomAccessFile ( file, "r" ) ;
randomAccessFile. read ( ) ;
randomAccessFile. seek ( 3 ) ;
byte [ ] bytes = new byte [ 1024 ] ;
int len = randomAccessFile. read ( bytes) ;
System . out. println ( "len = " + len) ;
System . out. println ( "str = " + new String ( bytes, 0 , len) ) ;
}
@Test
public void write ( ) throws Exception {
File file = new File ( "D:/E_DISK/IDEAJavaCode/BreakingPointFile/a.txt" ) ;
RandomAccessFile randomAccessFile = new RandomAccessFile ( file, "rw" ) ;
String str = "zhangsan" ;
randomAccessFile. write ( str. getBytes ( StandardCharsets . UTF_8) ) ;
}
}
2.2 单线程的文件复制
package com. liu. learn ;
import org. junit. Test ;
import java. io. File ;
import java. io. FileInputStream ;
import java. io. FileOutputStream ;
import java. io. IOException ;
public class RandomAccessFileTest2 {
@Test
public void SingleFile ( ) {
FileInputStream fis = null ;
FileOutputStream fos = null ;
try {
File file = new File ( "C:/Users/Administrator/Desktop/PCQQ2021.exe" ) ;
fis = new FileInputStream ( file) ;
fos = new FileOutputStream ( "D:\\360Downloads\\xxx.exe" ) ;
byte [ ] bytes = new byte [ 1024 * 8 ] ;
int len = - 1 ;
long start = System . currentTimeMillis ( ) ;
while ( ( len = fis. read ( bytes) ) != - 1 ) {
fos. write ( bytes, 0 , len) ;
}
long end = System . currentTimeMillis ( ) ;
System . out. println ( "总耗时: " + ( end - start) ) ;
System . out. println ( "文件复制完成~~~" ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
} finally {
if ( fis != null ) {
try {
fis. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
if ( fos != null ) {
try {
fos. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
}
}
}
2.3 多线程下的文件复制
package com. liu. learn ;
import java. io. File ;
import java. io. IOException ;
import java. io. RandomAccessFile ;
import java. util. ArrayList ;
public class RandomAccessFileTest3 {
public static void main ( String [ ] args) {
File file = new File ( "C:/Users/Administrator/Desktop/PCQQ2021.exe" ) ;
ArrayList < Thread > threadArrayList = new ArrayList < > ( ) ;
int threadNum = 5 ;
long length = file. length ( ) ;
int partLen = ( int ) Math . ceil ( length / threadNum) ;
for ( int i = 0 ; i < threadNum; i++ ) {
final int k = i;
Thread thread = new Thread ( ( ) -> {
try {
RandomAccessFile rafIn = new RandomAccessFile ( file, "r" ) ;
RandomAccessFile rafOut = new RandomAccessFile ( "D:/360Downloads/xxx.exe" , "rw" ) ;
rafIn. seek ( k * partLen) ;
rafOut. seek ( k * partLen) ;
int plen = 0 , len = - 1 ;
byte [ ] bytes = new byte [ 1024 * 8 ] ;
while ( true ) {
len = rafIn. read ( bytes) ;
if ( len == - 1 ) {
break ;
}
plen += len;
rafOut. write ( bytes, 0 , len) ;
if ( plen >= partLen) {
break ;
}
}
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
} ) ;
thread. start ( ) ;
threadArrayList. add ( thread) ;
}
long start = System . currentTimeMillis ( ) ;
for ( Thread thread : threadArrayList) {
try {
thread. join ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
long end = System . currentTimeMillis ( ) ;
System . out. println ( "总耗时: " + ( end - start) ) ;
System . out. println ( "文件复制完成~~~" ) ;
}
}
2.4 断点续传的实现
package com. liu. learn ;
import java. io. * ;
import java. nio. charset. StandardCharsets ;
import java. util. ArrayList ;
import java. util. StringJoiner ;
import java. util. concurrent. ConcurrentHashMap ;
public class RandomAccessFileTest4 {
public static void main ( String [ ] args) throws Exception {
File file = new File ( "C:/Users/Administrator/Desktop/PCQQ2021.exe" ) ;
ConcurrentHashMap < Integer , Integer > map = new ConcurrentHashMap < > ( ) ;
ArrayList < Thread > threadArrayList = new ArrayList < > ( ) ;
int threadNum = 5 ;
long length = file. length ( ) ;
int partLen = ( int ) Math . ceil ( length / threadNum) ;
String logFile = "D:/360Downloads/xxx.exe.log" ;
String [ ] data = null ;
File fl = new File ( logFile) ;
if ( fl. exists ( ) ) {
BufferedReader reader = new BufferedReader ( new FileReader ( fl) ) ;
String line = reader. readLine ( ) ;
data = line. split ( "," ) ;
reader. close ( ) ;
}
final String [ ] _data = data;
for ( int i = 0 ; i < threadNum; i++ ) {
final int k = i;
Thread thread = new Thread ( ( ) -> {
RandomAccessFile log = null ;
try {
RandomAccessFile rafIn = new RandomAccessFile ( file, "r" ) ;
RandomAccessFile rafOut = new RandomAccessFile ( "D:/360Downloads/xxx.exe" , "rw" ) ;
log = new RandomAccessFile ( logFile, "rw" ) ;
rafIn. seek ( _data == null ? k * partLen : Integer . parseInt ( _data[ k] ) ) ;
rafOut. seek ( _data == null ? k * partLen : Integer . parseInt ( _data[ k] ) ) ;
int plen = 0 , len = - 1 ;
byte [ ] bytes = new byte [ 1024 * 8 ] ;
while ( true ) {
len = rafIn. read ( bytes) ;
if ( len == - 1 ) {
break ;
}
plen += len;
map. put ( k, plen + ( _data == null ? k * partLen : Integer . parseInt ( _data[ k] ) ) ) ;
rafOut. write ( bytes, 0 , len) ;
log. seek ( 0 ) ;
StringJoiner joiner = new StringJoiner ( "," ) ;
map. forEach ( ( key, val) -> {
String . valueOf ( val) ;
} ) ;
log. write ( joiner. toString ( ) . getBytes ( StandardCharsets . UTF_8) ) ;
if ( plen + ( _data == null ? k * partLen : Integer . parseInt ( _data[ k] ) ) >= ( k + 1 ) * partLen) {
break ;
}
}
} catch ( IOException e) {
e. printStackTrace ( ) ;
} finally {
if ( log != null ) {
try {
log. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
}
} ) ;
thread. start ( ) ;
threadArrayList. add ( thread) ;
}
long start = System . currentTimeMillis ( ) ;
for ( Thread thread : threadArrayList) {
try {
thread. join ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
fl. delete ( ) ;
long end = System . currentTimeMillis ( ) ;
System . out. println ( "总耗时: " + ( end - start) ) ;
System . out. println ( "文件复制完成~~~" ) ;
}
}