HttpURLConnection断点下载
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import android.app.Activity; import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.Toast; public class MainActivity extends Activity { private EditText etPath; private EditText etThread; private LinearLayout llContent; int threadCount = 3; private String path; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etPath = (EditText) findViewById(R.id.et_path); etThread = (EditText) findViewById(R.id.et_thread); llContent = (LinearLayout) findViewById(R.id.ll_content); } public void download(View v) { path = etPath.getText().toString().trim(); String count = etThread.getText().toString().trim(); if (TextUtils.isEmpty(path) || !path.startsWith("http")) { Toast.makeText(this, "请输入正确的网址,否则,兄弟我没法干活。。。", 0).show(); return; } if (!TextUtils.isEmpty(count)) { threadCount = Integer.valueOf(count); } // 移除所有的view llContent.removeAllViews(); // 有多少个线程,就加载多少个进度条 for (int i = 0; i < threadCount; i++) { ProgressBar pb = (ProgressBar) View.inflate(this, R.layout.progressbar, null); llContent.addView(pb); } // 开启线程 new Thread() { public void run() { requestNet4DownLoad(); } }.start(); } /** * 下载 */ private void requestNet4DownLoad() { try { // 1. 在客户端创建和服务器资源一样大小的空文件 URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(3000); conn.setRequestMethod("GET"); int code = conn.getResponseCode(); // 服务器资源文件的大小 int fileLength = 0; if (code == 200) { fileLength = conn.getContentLength(); System.out.println("文件大小:" + fileLength); // //可选,可以不写,检测硬盘的空间够不够用 // RandomAccessFile raf = new RandomAccessFile(getFilePath(), // "rw"); // //在硬盘上创建控件 // raf.setLength(fileLength); // raf.close(); } // 每个线程下载的区块大小 int blockSize = fileLength / threadCount; // 2. 客户端开启多个线程去下载服务器的资源 for (int threadId = 0; threadId < threadCount; threadId++) { int startIndex = threadId * blockSize; int endIndex = (threadId + 1) * blockSize - 1; // 最后一个线程,修正下载的结束位置 if (threadId == threadCount - 1) { endIndex = fileLength - 1; } // 开启线程 new DownLoadThread(startIndex, endIndex, threadId).start(); } } catch (Exception e) { e.printStackTrace(); } } class DownLoadThread extends Thread { //开始位置 int startIndex; //结束位置 int endIndex; //线程ID int threadId; //断点的位置 int lastDownPos; private ProgressBar mPb; //最大的进度 int maxProgress; //当前下载的进度 int progress; //理论上开始下载的位置 int fistIndex; public DownLoadThread(int startIndex, int endIndex, int threadId) { super(); progress = startIndex;//初始化 fistIndex = startIndex; this.startIndex = startIndex; this.endIndex = endIndex; this.threadId = threadId; lastDownPos = startIndex;//初始 mPb = (ProgressBar) llContent.getChildAt(threadId); //设置最大的进度 maxProgress = endIndex - startIndex; mPb.setMax(maxProgress); } @Override public void run() { super.run(); System.out.println("理论上线程 : "+ threadId + " : "+ startIndex+" ~ "+endIndex) try { File tmpFile = new File(getFileTmpPath(threadId)); if (tmpFile != null && tmpFile.exists() && tmpFile.length() > 0) { FileInputStream fis = new FileInputStream(tmpFile); BufferedReader br = new BufferedReader(new InputStreamReader(fis)); int text = Integer.valueOf(br.readLine()); lastDownPos = text;//多次断点 startIndex = lastDownPos; //接受上一次断点的位置请求网络 br.close(); System.out.println("断点后线程 : "+ threadId + " : "+ startIndex+" ~ "+endIndex); } URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(3000); //重要,设置请求的范围 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex); //部分请求成功 206 int code = conn.getResponseCode(); System.out.println(" code = "+code); if (code == 206) { RandomAccessFile raf = new RandomAccessFile(getFilePath(), "rw"); //重要,写文件之前定位 raf.seek(startIndex); //获取这个线程对应的一块资源 InputStream is = conn.getInputStream(); byte[] buffer = new byte[512]; int len = -1; while((len = is.read(buffer)) != -1){ //计算存储的位置 lastDownPos += len; RandomAccessFile r = new RandomAccessFile(getFileTmpPath(threadId), "rwd"); String pos = String.valueOf(lastDownPos); //存储断点的位置 r.write(pos.getBytes()); r.close(); raf.write(buffer, 0, len); //设置进度条的进度 progress = lastDownPos - fistIndex; mPb.setProgress(progress); } raf.close(); } // 3. 每个线程都下载完毕,整个资源就下载完了 System.out.println("线程 "+threadId+" 干完活了!"); //删除临时的进度文件 System.out.println(tmpFile.delete()); } catch (Exception e) { e.printStackTrace(); } } } /** * 获取文件的存储路径 */ String getFilePath(){ int index = path.lastIndexOf("/")+1; return "/mnt/sdcard/"+path.substring(index); } ** * 存储进度的临时文件 */ String getFileTmpPath(int threadId){ return getFilePath()+threadId+".txt"; } }
import java.io.ByteArrayOutputStream; import java.io.InputStream; /** * 操作字符串 */ public class StringUtils { /** * 从流中转成字符串 * * @param is * 输入流 * @return null表示失败 */ public static String parseStream2Str(InputStream is) { //内存输出流 ByteArrayOutputStream baos = new ByteArrayOutputStream(); int len = -1; byte[] buffer = new byte[1024*8]; try { while((len = is.read(buffer)) != -1){ baos.write(buffer, 0, len); } return new String(baos.toByteArray()); } catch (Exception e) { e.printStackTrace(); return null; } } }
最后,关注【码上加油站】微信公众号后,有疑惑有问题想加油的小伙伴可以码上加入社群,让我们一起码上加油吧!!!