2025-02-17

單線程下載很簡單,就是開啟一個線程去下載資源再進行本地保存;

多線程下載是通過RandomAccessFile(隨機文件讀寫操作類)來設置每個線程讀取文件的起始點位置,起始點之間的長度即為該線程需要下載的文件大小

下載開始位置:線程id*每條線程下載的數據長度 = ?

下載結束位置:(線程id+1)*每條線程下載的數據長度-1=?

這樣比如文件大小:size,線程數:threads,則每個線程的下載量:size/threads;但是這是整除的情況,如果考慮到不能整除的情況:則前threads-1個線程下載量為size/threads,最後一個線程的下載量:size/threads+size%threads
File_downactivity.java代碼 
package file.down; 
 
import java.io.File; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.net.URLConnection; 
 
import javax.security.auth.PrivateCredentialPermission; 
 
import android.R.integer; 
import android.app.Activity; 
import android.os.Bundle; 
import android.os.Handler; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.view.ViewDebug.FlagToString; 
import android.widget.Button; 
import android.widget.EditText; 
import android.widget.ProgressBar; 
import android.widget.TextView; 
 
public class File_downActivity extends Activity { 
    private Button but1,but2; 
    private EditText etUrl; 
    private ProgressBar bar1,bar2; 
    private TextView tv1,tv2; 
    private boolean flag = true; 
    private int temp = 0; 
    private int downLoadedSize = 0; 
    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
        etUrl = (EditText) findViewById(R.id.downloadUrl); 
         
        but1 = (Button) findViewById(R.id.but1); 
        but2 = (Button) findViewById(R.id.but2); 
         
        bar1 = (ProgressBar) findViewById(R.id.downloadProgressBar1); 
        bar2 = (ProgressBar) findViewById(R.id.downloadProgressBar2); 
         
        tv1 = (TextView) findViewById(R.id.tv1); 
        tv2 = (TextView) findViewById(R.id.tv2); 
         
         
        //單線程下載 
        but1.setOnClickListener(new OnClickListener() { 
             
            @Override 
            public void onClick(View v) { 
                if(DownUtil.isExistSdCard()){ 
                    if(DownUtil.checkNet(File_downActivity.this)){ 
                        if(DownUtil.creatDir(DownUtil.path1)){ 
                            thread.start(); 
                        } 
                    } 
                } 
            } 
        }); 
        //多線程下載 
        but2.setOnClickListener(new OnClickListener() { 
             
            @Override 
            public void onClick(View v) { 
                mulThread.start(); 
            } 
        }); 
    } 
    @Override 
    protected void onDestroy() { 
        super.onDestroy(); 
        DownUtil.downLoadSize = 0; 
    } 
    /** 
     * 單線程下載 
     */ 
    private Thread thread = new Thread(new Runnable() { 
         
        @Override 
        public void run() { 
                 
                DownUtil.fileDown1(etUrl.getText().toString(), DownUtil.savePath1, handler); 
                bar1.setMax(DownUtil.fileSize); 
        } 
    }); 
    /** 
     * 多線程下載(主線程類) 
     */ 
    private Thread mulThread = new Thread(new Runnable() { 
        private int blockSize,downLoadSizeMore; 
        private int threadNum = 5;//線程數 
         
        @Override 
        public void run() { 
//          MulDownThread[] threads = new MulDownThread[threadNum]; 
            try { 
                URL url = new URL(etUrl.getText().toString()); 
                URLConnection connection = url.openConnection(); 
                DownUtil.fileSize2 = connection.getContentLength(); 
                if(DownUtil.fileSize2 <= 0){ 
                    return; 
                } 
            } catch (Exception e) { 
                e.printStackTrace(); 
            } 
            //計算每個線程下載的數據量 
            blockSize = DownUtil.fileSize2 / threadNum; 
            //解決整除後餘下的數據量 
            downLoadSizeMore = DownUtil.fileSize2 % threadNum; 
            bar2.setMax(100); 
            if(DownUtil.creatDir(DownUtil.path2)){ 
                 
                File file = new File(DownUtil.savePath2 + "/" + etUrl.getText().toString().substring(etUrl.getText().toString().lastIndexOf("/") + 1)); 
                for(int i=0;i<threadNum;i++){ 
                    if(i < threadNum – 1){ 
                         
                        //啟動線程,分別下載文件 
                        MulDownThread thread = new MulDownThread(etUrl.getText().toString(), file, i*blockSize, (i + 1) * blockSize – 1,handler); 
                        thread.start(); 
                    }else{//最後那個線程下載的文件長度要等於每個線程平均下載量加上整除後的餘數 
                        MulDownThread thread = new MulDownThread(etUrl.getText().toString(), file, i*blockSize, (i + 1) * blockSize – 1 + downLoadSizeMore,handler); 
                        thread.start(); 
                    } 
//                  //啟動線程,分別下載文件 
//                  MulDownThread thread = new MulDownThread(etUrl.getText().toString(), file, i*blockSize, (i + 1) * blockSize -1); 
//                  thread.start(); 
//                  handler.sendEmptyMessage(10); 
                } 
//              boolean finished = false; 
//              while(!finished){ 
//                  //先把整除的餘數搞定 
//                  downLoadedSize = downLoadSizeMore; 
//                  finished = true; 
//                  for(int i = 0;i<threads.length;i++){ 
//                      downLoadedSize += threads[i].downLoadSize; 
//                      if(!threads[i].isFinisthed){ 
//                          finished = false; 
//                      } 
//                  } 
//                  handler.sendEmptyMessage(10); 
//              } 
            } 
        } 
    }); 
    private Handler handler = new Handler(){ 
        public void handleMessage(android.os.Message msg) { 
            switch (msg.what) { 
            case 0: 
                tv1.setText("無法獲取文件大小"); 
                break; 
            case -1: 
                tv1.setText("下載完成"); 
                bar1.setProgress(100); 
                but1.setClickable(false); 
                break; 
 
            case 1: 
                but1.setClickable(false); 
                int result = Double.valueOf(((Integer.parseInt(msg.obj.toString())*1.0 / DownUtil.fileSize * 100))).intValue(); 
                bar1.setProgress(result); 
                tv1.setText(result + "%"); 
                break; 
            case 2: 
                tv1.setText("文件獲取錯誤"); 
                break; 
            case 10://多線程下載更新進度條 
                but2.setClickable(false); 
                int result2 = (Double 
                        .valueOf((Integer.parseInt(msg.obj.toString()) * 1.0 / DownUtil.fileSize2 * 100))) 
                        .intValue(); 
                bar2.setProgress(result2); 
                if(result2 == 100){ 
                    tv2.setText("下載完成"); 
                }else{ 
                     
                    tv2.setText(result2 + "%"); 
                } 
                break; 
            } 
        }; 
    }; 

 
Muldownthread.java代碼 
package file.down; 
 
import java.io.File; 
 
import android.os.Handler; 
/** 
 * 線程類 
 * @author Administrator 
 * 
 */ 
public class MulDownThread extends Thread { 
 
    private String url; 
    private File file; 
    private int startPosition; 
    private int endPosition; 
    private Handler handler; 
     
     
    public MulDownThread(String url,File file,int startPosition,int endPosition,Handler handler){ 
        this.url = url; 
        this.file = file; 
        this.startPosition = startPosition; 
        this.endPosition = endPosition; 
        this.handler = handler; 
    } 
     
    @Override 
    public void run() { 
        DownUtil.fileDown2(url, file, startPosition, endPosition,handler); 
    } 
 
     
     

 
Downutil.java代碼 
package file.down; 
 
import java.io.BufferedInputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.RandomAccessFile; 
import java.net.HttpURLConnection; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.net.URLConnection; 
 
import android.R.integer; 
import android.R.string; 
import android.content.Context; 
import android.net.ConnectivityManager; 
import android.net.NetworkInfo; 
import android.os.Environment; 
import android.os.Handler; 
import android.os.Message; 
import android.util.Log; 
 
public class DownUtil { 
 
    //單線程下載目錄 
    public static String path1 = "/down1/"; 
    public static String savePath1; 
    //多線程下載目錄 
    public static String path2 = "/down2/"; 
    public static String savePath2; 
     
    public static String fileName; 
    public static int fileSize; 
    public static int fileSize2; 
     
    private static int curPosition; 
    //已下載的文件大小 
    public static int downLoadSize; 
    //標示當前線程是否下載完成 
    public static boolean finished = false; 
    /** 
     * 判斷sd卡是否存在 
     * Environment.MEDIA_MOUNTED 判斷SD卡是否存在 
     * @return 
     */ 
    public static boolean isExistSdCard(){ 
        boolean flag = true; 
        if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ 
            flag = false; 
        } 
        return flag; 
    } 
    /** 
     * 創建目錄 
     * @param dir 
     * @return 
     */ 
    public static boolean creatDir(String dir){ 
        boolean flag = false; 
        File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + dir); 
        if(!file.exists()){ 
            file.mkdir(); 
            if(file.exists()){ 
                flag = true; 
                savePath1 = file.getAbsolutePath(); 
                savePath2 = file.getAbsolutePath(); 
            } 
        }else{ 
            flag = true; 
            savePath1 = file.getAbsolutePath(); 
            savePath2 = file.getAbsolutePath(); 
        } 
        return flag; 
    } 
    /** 
     * 檢查網絡是否可用 
     * @return 
     */ 
    public static boolean checkNet(Context context){ 
        boolean flag = false; 
        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE); 
        NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); 
        NetworkInfo mobile = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); 
        if(wifi.isConnectedOrConnecting() || mobile.isConnectedOrConnecting()){ 
            flag = true; 
        } 
        return flag; 
    } 
    /** 
     * 單線程文件下載 
     * @param url 
     * @param path 
     */ 
    public static void fileDown1(String url,String path,Handler handler) { 
        Log.v("=path=", path+"="); 
        Message message = new Message(); 
        if(!"".equals(url)){ 
            fileName = url.substring(url.lastIndexOf("/") + 1); 
            InputStream inputStream = null; 
            FileOutputStream outputStream = null; 
            try { 
                URL myuUrl = new URL(url); 
                URLConnection connection = myuUrl.openConnection(); 
                connection.connect(); 
                inputStream = connection.getInputStream(); 
                fileSize = connection.getContentLength(); 
                Log.v("=fileSize=", DownUtil.fileSize+"="); 
                if(fileSize <= 0){ 
                    message.what = 0; 
                    handler.sendMessage(message); 
                    return; 
                }else{ 
                    outputStream = new FileOutputStream(path +"/"+ fileName); 
                    //存儲文件 
                    byte buf[] = new byte[inputStream.available()]; 
                    int len = 0; 
                    int temp = 0; 
                    Log.v("=available=", inputStream.available()+"="); 
                    while ((len = inputStream.read(buf)) != -1) { 
                        outputStream.write(buf, 0, len); 
                        temp += len; 
                        Message message2 = new Message(); 
                        message2.what = 1; 
                        message2.obj = temp;//下載的百分比 
                        handler.sendMessage(message2); 
                    } 
                    Message msg = new Message(); 
                    //通知下載完成 
                    msg.what = -1; 
                    handler.sendMessage(msg); 
                } 
            } catch (Exception e) { 
                message.what = 2; 
                handler.sendMessage(message); 
                return; 
            }finally{ 
                try { 
                     
                    if(inputStream != null || outputStream != null){ 
                        outputStream.close(); 
                        inputStream.close(); 
                    } 
                } catch (Exception e2) { 
                } 
            } 
        } 
    } 
    /** 
     * 多線程下載文件 
     * @param url 
     * @param path 
     * @param handler 
     */ 
    public static void fileDown2(String url,File file,int startPosition,int endPosition,Handler handler){ 
        URLConnection connection = null; 
        InputStream inputStream = null; 
        BufferedInputStream bis = null; 
        RandomAccessFile raf = null; 
        try { 
            URL url2 = new URL(url); 
            connection = url2.openConnection(); 
//          connection.connect(); 
            connection.setAllowUserInteraction(true); 
            // 設置當前線程下載的起點,終點 
            connection.setRequestProperty("Range", "bytes=" + startPosition + "-" 
                    + endPosition); 
            inputStream = connection.getInputStream(); 
            if(fileSize2 <= 0){ 
                return; 
            } 
            //對文件進行隨機讀寫操作 
            raf = new RandomAccessFile(file,"rw"); 
            //設置開始寫文件的位置 
            raf.seek(startPosition); 
            bis = new BufferedInputStream(inputStream); 
            //開始循環以流的形式讀寫文件 
//          curPosition = startPosition; 
            //每個線程需要讀取文件的長度 
//          int temp = endPosition – startPosition; 
            byte[] buffer = new byte[1024]; 
            int length = 0; 
            while ((length = inputStream.read(buffer)) != -1) { 
                raf.write(buffer, 0, length); 
                downLoadSize += length; 
                Message message = new Message(); 
                message.what = 10; 
                message.obj = downLoadSize; 
                handler.sendMessage(message); 
            } 
//          while (curPosition < endPosition) { 
//              int len = bis.read(buffer, 0, temp); 
//              if(len == -1){ 
//                  break; 
//              } 
//              Log.v("=len=", "="+len); 
//              raf.write(buffer, 0, len); 
//              curPosition += len; 
////                if(curPosition > endPosition){ 
////                    downLoadSize += len – (curPosition – endPosition) + 1; 
////                    Log.v("=downLoadSize=", "="+downLoadSize); 
////                }else{ 
//                  downLoadSize += len; 
////                } 
//                  Message message = new Message(); 
//                  message.what = 10; 
//                  message.obj = downLoadSize; 
//                  handler.sendMessage(message); 
//          } 
        } catch (Exception e) { 
            e.printStackTrace(); 
        }finally{ 
            try { 
                if(inputStream != null || raf != null || bis != null){ 
                    bis.close(); 
                    raf.close(); 
                    inputStream.close(); 
                } 
            } catch (Exception e2) { 
            } 
        } 
    } 

作者“shufeipenglove-163-com”
 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *