多线程下载

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
package com.example.mutildownloader2;
  
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
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;
  
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
  
public class MainActivity extends Activity {
    protected static final int DOWN_LOAD_ERROR = 1;
    protected static final int SERVER_ERROR = 2;
    public static final int DOWN_LAOD_FINSIH = 3;
    public static final int UPDATE_TEXT = 4;
    private EditText et_path;
    private ProgressBar pb; //下载的进度条.
    public static int threadCount = 3;
    public static int runningThread = 3 ;
      
    public int currentProcess = 0; //当前进度.
      
    private TextView tv_process;
      
      
    private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case DOWN_LOAD_ERROR:
                Toast.makeText(getApplicationContext(), "下载失败", 0).show();
                break;
            case SERVER_ERROR:
                Toast.makeText(getApplicationContext(), "服务器 错误,下载失败", 0).show();
                break;
            case DOWN_LAOD_FINSIH:
                Toast.makeText(getApplicationContext(), "文件下载完毕", 0).show();
                break;
            case UPDATE_TEXT:
                tv_process.setText("当前进度:"+pb.getProgress()*100/pb.getMax());
                break;
            }
              
              
        };
    };
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_path = (EditText) this.findViewById(R.id.et_path);
        pb = (ProgressBar) findViewById(R.id.pb);
        tv_process = (TextView) findViewById(R.id.tv_process);
    }
  
    public void downLoad(View view) {
        final String path = et_path.getText().toString().trim();
        if (TextUtils.isEmpty(path)) {
            Toast.makeText(this, "下载路径错误", 0).show();
            return;
        }
        currentProcess = 0;
        new Thread() {
            public void run() {
                try {
                    //String path = "http://192.168.1.100:8080/360.exe";
                    URL url = new URL(path);
                    HttpURLConnection conn = (HttpURLConnection) url
                            .openConnection();
                    conn.setConnectTimeout(5000);
                    conn.setRequestMethod("GET");
                    int code = conn.getResponseCode();
                    if (code == 200) {
                        // 服务器返回的数据的长度 实际上就是文件的长度
                        int length = conn.getContentLength();
                        pb.setMax(length);//设置进度条的最大值.
                        System.out.println("文件总长度:" + length);
                        // 在客户端本地 创建出来一个大小跟服务器端文件一样大小的临时文件
                        RandomAccessFile raf = new RandomAccessFile("/sdcard/setup.exe"
                                "rwd");
                        // 指定创建的这个文件的长度
                        raf.setLength(length);
                        raf.close();
  
                        // 假设是3个线程去下载资源.
                        // 平均每一个线程下载的文件的大小.
                        int blockSize = length / threadCount;
                        for (int threadId = 1; threadId <= threadCount; threadId++) {
                            // 第一个线程下载的开始位置
                            int startIndex = (threadId - 1) * blockSize;
                            int endIndex = threadId * blockSize - 1;
                            if (threadId == threadCount) {// 最后一个线程 下载的长度 要稍微长一点
                                endIndex = length;
                            }
                            System.out.println("线程:" + threadId + "下载:---"
                                    + startIndex + "--->" + endIndex);
                            new DownloadThread(path, threadId, startIndex, endIndex)
                                    .start();
                        }
  
                    } else {
                        System.out.println("服务器错误.");
                        Message msg = new Message();
                        msg.what = SERVER_ERROR;
                        handler.sendMessage(msg);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Message msg = new Message();
                    msg.what = DOWN_LOAD_ERROR;
                    handler.sendMessage(msg);
                      
                      
                }
  
            };
        }.start();
  
    }
      
      
    /**
     * 下载文件的子线程 每一个线程 下载对应位置的文件
     
     * @author Administrator
     
     */
    public  class DownloadThread extends Thread {
        private int threadId;
        private int startIndex;
        private int endIndex;
        private String path;
  
        /**
         * @param path
         *            下载文件在服务器上的路径
         * @param threadId
         *            线程id
         * @param startIndex
         *            线程下载的开始位置
         * @param endIndex
         *            线程下载的结束位置.
         */
        public DownloadThread(String path, int threadId, int startIndex,
                int endIndex) {
            this.threadId = threadId;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.path = path;
        }
  
        @Override
        public void run() {
            try {
  
                // 检查是否存在 记录下载长度的文件 ,如果存在读取这个文件的数据.
                //------------------替换成存数据库-------------------------
                File tempFile = new File("/sdcard/"+threadId + ".txt");
                if (tempFile.exists() && tempFile.length() > 0) {
                    FileInputStream fis = new FileInputStream(tempFile);
                    byte[] temp = new byte[1024];
                    int leng = fis.read(temp);
                    String downloadLen = new String(temp, 0, leng);
                    int downloadlenInt = Integer.parseInt(downloadLen);
                      
                    int alreadyDownlodint = downloadlenInt - startIndex ;
                    currentProcess+=alreadyDownlodint; //计算上次断点 已经下载的文件的长度.
                      
                    startIndex = downloadlenInt;//修改下载的真实的开始位置.
                    fis.close();
                }
                //--------------------------------------------
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url
                        .openConnection();
                conn.setRequestMethod("GET");
                // 重要: 请求服务器下载部分的文件 指定文件的位置.
                conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
                        + endIndex);
                System.out.println("线程真实下载:" + threadId + "下载:---" + startIndex
                        + "--->" + endIndex);
                conn.setConnectTimeout(5000);
                int code = conn.getResponseCode(); // 从服务器请求全部资源 200 ok
                                                    // 如果从服务器请求部分资源 206 ok
                if (code == 206) {
                    InputStream is = conn.getInputStream();// 已经设置了 请求的位置
                    RandomAccessFile raf = new RandomAccessFile("/sdcard/setup.exe",
                            "rwd");
                    // 随机写文件的时候 从哪个位置开始写
                    raf.seek(startIndex);// 定位文件
                    int len = 0;
                    byte[] buffer = new byte[1024];
                    int total = 0;// 已经下载的数据长度
                    while ((len = is.read(buffer)) != -1) {
                        RandomAccessFile file = new RandomAccessFile("/sdcard/"+threadId
                                + ".txt", "rwd");// 作用: 记录当前线程下载的数据长度
                        raf.write(buffer, 0, len);
                        total += len;
                        //System.out.println("线程:" + threadId + "total:" + total); 
                        file.write(( total+startIndex+"").getBytes());//记录的是 下载位置.
                        file.close();
                          
                        //更新进度条
                        synchronized (MainActivity.this) {
                            currentProcess+=len;//获取所有线程下载的总进度.
                            pb.setProgress(currentProcess);//更改界面上progressbar 进度条的进度
                            //特殊情况 progressbar progressdialog 进度条对话框 可以直接在子线程里面更新ui  内部代码 特殊处理
                            Message msg = Message.obtain();//复用旧的消息 避免创建新的消息
                            msg.what = UPDATE_TEXT;
                            handler.sendMessage(msg);
                        }
                          
                    }
                    is.close();
                    raf.close();
                    System.out.println("线程:" + threadId + "下载完毕了...");
                } else {
                    System.out.println("线程:" + threadId + "下载失败...");
                }
                  
//              File deleteFile = new File("/sdcard/"+threadId+".txt");
//              deleteFile.delete();//当线程下载完毕后 清楚掉 下载的记录
                  
                //如何去判断应用程序已经下载完毕.
                  
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                threadFinish();
            }
  
        }
  
        private synchronized void threadFinish() {
            runningThread --;
            if(runningThread==0){//所有的线程 已经执行完毕了.
                for(int i= 1;i<=3;i++){
                    File file = new File("/sdcard/"+i+".txt");
                    file.delete();
                }
                System.out.println("文件下载完毕 ,删除所有的下载记录.");
                Message msg = new Message();
                msg.what = DOWN_LAOD_FINSIH;
                handler.sendMessage(msg);
            }
        }
    }
}

 

 

 

 



来自为知笔记(Wiz)


posted on 2014-04-28 14:04  转折点人生  阅读(513)  评论(0)    收藏  举报