1 package com.thread;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.RandomAccessFile;
7 import java.net.HttpURLConnection;
8 import java.net.URL;
9
10 public class MultiDownLoad {
11 private final static int threadCount = 4;
12
13 public static void main(String[] args) throws Exception {
14 URL url = new URL("http://ubmcmm.baidustatic.com/media/v1/0f000Qk-RgkVYN5NV_NaO6.jpg");
15 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
16 long contentLength = conn.getContentLengthLong();
17 long perLength = contentLength/threadCount;
18 File file = new File("E:/123.jpg");
19 //为每个线程分配一个随机写入流
20 RandomAccessFile[] raf = new RandomAccessFile[threadCount];
21 InputStream[]is = new InputStream[threadCount];
22 for(int i=0;i<threadCount;i++){
23 //确定每个线程应该写入的起始位置和至少写入字节数
24 //最后一个线程负责剩下的所有字节(小于其他线程负责的字节数)
25 //开启线程
26 long start = i*perLength;
27 raf[i] = new RandomAccessFile(file, "rw");
28 is[i] = url.openStream();
29 if(i != threadCount-1){
30 new Thread(new DownLoad(start,perLength,raf[i],is[i])).start();
31 }else {
32 long specialEnd = contentLength - perLength*(threadCount-1);
33 new Thread(new DownLoad(start,specialEnd,raf[i],is[i])).start();
34 }
35
36 }
37 }
38
39 }
40 class DownLoad implements Runnable{
41
42 private final int BUFFSIZE = 1024;
43 private long start;
44 private long end;
45 private RandomAccessFile raf;
46 private InputStream is;
47
48 public DownLoad(long start, long end, RandomAccessFile raf,
49 InputStream is) {
50 this.start = start;
51 this.end = end;
52 this.raf = raf;
53 this.is = is;
54 }
55
56 @Override
57 public void run() {
58 try {
59 is.skip(start);
60 raf.seek(start);
61 byte[] buf = new byte[BUFFSIZE];
62 int times = (int) ((end/BUFFSIZE)+4);
63 //某个线程的下载超过了该线程应该下载量 是没有问题的 因为后面的线程会在它的起始位置重新写入
64 //但是如果该线程下载的量不足 就会导致图片显示异常!!
65 //由于每次读取buf缓冲区的字节 但并不是每次都能真实的读满
66 //防止下载量不足 让改线程多读几次故 +4
67 for(int i = 0; i<times;i++){
68 int a = is.read(buf);
69 if(a<0){
70 break;
71 }
72 raf.write(buf,0,a);
73 }
74 } catch (IOException e) {
75 e.printStackTrace();
76 }finally{
77 try {
78 is.close();
79 } catch (IOException e) {
80 e.printStackTrace();
81 }
82 try {
83 raf.close();
84 } catch (IOException e) {
85 e.printStackTrace();
86 }
87 }
88
89 }
90
91 /**
92 * @return the start
93 */
94 public long getStart() {
95 return start;
96 }
97
98 /**
99 * @param start the start to set
100 */
101 public void setStart(long start) {
102 this.start = start;
103 }
104
105 /**
106 * @return the end
107 */
108 public long getEnd() {
109 return end;
110 }
111
112 /**
113 * @param end the end to set
114 */
115 public void setEnd(long end) {
116 this.end = end;
117 }
118
119 /**
120 * @return the raf
121 */
122 public RandomAccessFile getRaf() {
123 return raf;
124 }
125
126 /**
127 * @param raf the raf to set
128 */
129 public void setRaf(RandomAccessFile raf) {
130 this.raf = raf;
131 }
132
133
134 /**
135 * @return the is
136 */
137 public InputStream getIs() {
138 return is;
139 }
140
141 /**
142 * @param is the is to set
143 */
144 public void setIs(InputStream is) {
145 this.is = is;
146 }
147
148 }