原理:
RandomAccessFile能够随机读取文件,可以读写指定位置的内容。所以我们可以开启n个下载线程,每个线程专门负责文件中的一段,当然下载也同样只是下载对应段的内容。
那怎么从网络上获取文件的特定段呢?
http 1.1提供了分段下载的功能,只需要设置好请求头就好了,如下:
conn.setRequestProperty(“Range”, “bytes=” + StartPos + “-” + EndPos);
请求的文件段为 [StartPos, EndPos] 。
RandomAccessFile类的常用方法:
- public RandomAccessFile(File file, String mode)throws FileNotFoundException 构造方法 接收File类的对象,指定操作路径,但是在设置时需要设置模式:”r”: 只读、”w”: 只写、”rw”: 读写。
- public RandomAccessFile(String name, String mode) throws FileNotFoundException 构造方法 不再使用File类对象表示文件,而是直接输入了一个固定的文件路径。
- public void close() throws IOException 关闭操作
- public int read(byte[] b) throws IOException 将内容读取到一个byte数组之中
- public final byte readByte() throws IOException 读取一个字节
- public final int readInt() throws IOException从文件中读取整型数据。
- public void seek(long pos) throws IOException 设置读指针的位置。
- public final void writeBytes(String s) throws IOException 将一个字符串写入到文件之中,按字节的方式处理。
- public final void writeInt(int v) throws IOException 将一个int型数据写入文件,长度为4位。
- public int skipBytes(int n) throws IOException 指针跳过多少个字节。
代码实现:
这里以下载Tomcat 7.086 为例子
url:http://apache.01link.hk/tomcat/tomcat-7/v7.0.86/bin/apache-tomcat-7.0.86.zip
DownloadFile.class
/***
* 要十分注意StartPos 和 EndPos 设置
* ***/
public class DownloadFile {
public final static String FileURL = "http://apache.01link.hk/tomcat/tomcat-7/v7.0.86/bin/apache-tomcat-7.0.86.zip";
public final static int COUNT = 3; //分段数
public static File SaveFile;
public static void main(String[] args) throws IOException {
URL url = new URL(FileURL);
//建立一个连接
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.connect();
int code = conn.getResponseCode();
int position = FileURL.lastIndexOf("/");
String fileName = FileURL.substring(position+1); //文件名
System.out.println("file name is :"+fileName);
if(code == 200){
int FileLength = conn.getContentLength(); //获取文件长度
System.out.println("文件总长度为:"+FileLength);
SaveFile = new File("/home/pzs/husin/filedownload/"+fileName);
RandomAccessFile raf = new RandomAccessFile(SaveFile,"rw"); //若没有该文件,则自动创建
raf.setLength(FileLength); //设置文件长度
raf.close();
//分块大小
int blockSize = FileLength / COUNT;
for(int i=0; i <= COUNT; i++){
int StartPos = i * blockSize;
int EndPos = (i+1) * blockSize - 1;
//最后一条线程EndPos = FileLength
if(i == COUNT){
EndPos = FileLength;
}
System.out.println("线程" + i + "下载的部分为:" + StartPos +"---" + EndPos);
new DownLoadThread(i,StartPos,EndPos,FileURL,SaveFile).start();
}
}
}
}
DownLoadThread.class
public class DownLoadThread extends Thread{
//线程id
private int threadId;
private int StartPos;
private int EndPos;
private String FileURL;
private File SaveFile;
public DownLoadThread(int threadId, int StartPos, int EndPos, String FileURL, File SaveFile){
this.threadId = threadId;
this.StartPos = StartPos;
this.EndPos = EndPos;
this.FileURL = FileURL;
this.SaveFile = SaveFile;
}
@Override
public void run() {
try {
URL url = new URL(FileURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(500);
conn.setRequestMethod("GET");
//请求文件段
conn.setRequestProperty("Range", "bytes=" + StartPos + "-" + EndPos);
int code = conn.getResponseCode();
//206表示文件分段请求,而不是整个文件请求
if(code == 206){
InputStream is = conn.getInputStream();
int len = 0;
byte[] buf = new byte[1024];
RandomAccessFile raf = new RandomAccessFile(SaveFile, "rw");
raf.seek(StartPos);
while((len = is.read(buf)) > 0) {
raf.write(buf, 0, len);
}
is.close();
System.out.println("线程" + threadId + "下载完毕!!");
}else{
System.out.println("不支持分段下载");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}