threadfile.seek(2097152); //从文件的什么位置开始写入数据
下图为原理图:
准备工作:
搭建Tomcat服务器,放置需要下载的资源,如下图所示的video1.avi
确认资源文件的大小为23,250,432byte
开始编写代码了.以下代码都是j2se的知识,因此可以直接创建一个j2se的工程来演示
<span style="font-family:Courier New;font-size:14px;">import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; /** * * @author Chenys * 多线程下载文件 * */ public class MultiThreadDownload { /** * 线程的数量 */ private static int threadCount = 3; /** * 每个下载区块的大小 */ private static long blocksize; public static void main(String[] args) throws IOException { // 服务器文件的路径 String path = "http://192.168.0.102:8080/video1.avi"; URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); int code = conn.getResponseCode(); if (code == 200) { // 得到服务器端返回的文件大小,单位byte,字节 long size = conn.getContentLength(); System.out.println("服务器文件的大小:" + size); // 计算每个blocksize的大小 blocksize = size / threadCount; /** * 1.首先在本地创建一个文件大小跟服务器一模一样的空白文件,RandomAccessFile类的实例支持对随机访问文件的读取和写入 * 参数1:目标文件 参数2:打开该文件的访问模式,"r" 以只读方式打开 ,"rw" 打开以便读取和写入 */ File file = new File("temp.avi"); RandomAccessFile raf = new RandomAccessFile(file, "rw"); raf.setLength(size);// 设置文件的大小 // 2.开启若干个子线程,分别下载对应的资源 for (int i = 1; i <= threadCount; i++) { long startIndex = (i - 1) * blocksize; // 由于服务端下载文件是从0开始的 long endIndex = i * blocksize - 1; if (i == threadCount) { // 最后一个线程 endIndex = size - 1; } System.out.println("开启线程:" + i + "下载的位置" + startIndex + "~"+ endIndex); new DownloadThread(path, i, startIndex, endIndex).start(); } } conn.disconnect(); } /** * 自定义下载线程 * @author Chenys * */ private static class DownloadThread extends Thread { private int threadId; // 线程id private long startIndex; // 开始下载的位置 private long endIndex; // 结束下载的位置 private String path; public DownloadThread(String path, int threadId, long startIndex, long endIndex) { this.path = path; this.threadId = threadId; this.startIndex = startIndex; this.endIndex = endIndex; } public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); //设置http协议请求头: 指定每条线程从文件的什么位置开始下载,下载到什么位置为止 conn.setRequestProperty("Range", "bytes=" + startIndex + "-"+ endIndex); int code = conn.getResponseCode(); System.out.println("服务器返回码code=" + code);// 如果是下载一部分资源,那么返回码是206 InputStream is = conn.getInputStream(); File file = new File("temp.avi"); RandomAccessFile raf = new RandomAccessFile(file, "rw"); // 指定文件的下载起始位置 raf.seek(startIndex); System.out.println("第" + threadId + "个线程写文件的开始位置" + String.valueOf(startIndex)); // 开始保存文件 int len = 0; byte[] buff = new byte[1024]; while ((len = is.read(buff)) != -1) { raf.write(buff, 0, len); } is.close(); raf.close(); System.out.println("线程" + threadId + "下载完毕了"); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } </span>
运行结果如下:
刷新工程目录,可以发现刚刚下载的temp.avi文件
打开工程的根目录,确认下载的文件大小是否和服务器上的文件大小一致