黑马Android76期学习笔记01基础--day05--Get,Post,HttpClient(过时)多线程下载,断点续传,多线程下载

1.Get方式提交数据
**StreamTool类**

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class StreamTool {
    public static  String readStream(InputStream inputStream) throws IOException {
        //定义 一个内存输出流
        ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
        int len=-1;
        byte[]buffer=new byte[1024];
        while ((len=inputStream.read(buffer))!=-1){
            byteArrayOutputStream.write(buffer,0,len);
        }
        inputStream.close();
        String content=new String(byteArrayOutputStream.toByteArray());
        return content;
    }
}

主activity

package com.fengray.ex053;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class MainActivity extends AppCompatActivity {
    private EditText edUserName,edPassWord;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initviews();
    }

    public void initviews(){
        edUserName=findViewById(R.id.edUserName);
        edPassWord=findViewById(R.id.edPassWord);
    }
    //Get方式提交
    public void btnGetClick(View view){
        String username=edUserName.getText().toString().trim();
        String password=edPassWord.getText().toString().trim();
        //定义get方式要提交的路径
        final String path="http://192.168.1.64/******username="+username+"&password="+password;
        //获取Url对象
        new Thread(){
            @Override
            public void run() {
                URL url= null;

                try {
                    url = new URL(path);
                    //获取HTTPURLConnection对象
                    HttpURLConnection connection=(HttpURLConnection)url.openConnection();
                    //设置Connection访问方式
                    connection.setRequestMethod("GET");
                    //设置超时时间
                    connection.setConnectTimeout(5000);
                    //获取返回的状态码
                    int code=connection.getResponseCode();
                    //判断状态码
                    if (code==200){
                        //获取流
                        InputStream inputStream=connection.getInputStream();
                        //
                        String content= StreamTool.readStream(inputStream);
                        //将服务器返回的数据返回到Toast里,不能再子线程上更新UI
                        showToast(content);

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }.start();
    }

    //Post方式提交
    public void btnPostClick(View view){
        String username=edUserName.getText().toString().trim();
        String password=edPassWord.getText().toString().trim();
    }

    //封装一个Toast方法,该toast方法执行在主线程当中
    public void showToast(final String content){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //该方法一定执行在主线程的
                Toast.makeText(getApplicationContext(), content, Toast.LENGTH_SHORT).show();
            }
        });
    }
}
2.Post方式提交数据

get方式和post方式的区别

  • 1、路径不同
  • 2、请求方式,post要自己组拼请求体的内容,post方式比get方式多了2个头信息,content-length,content-type
  • 3、通过请求体的方式把数据写歌服务器,以流的形式
    仅仅修改postClick方法
//Post方式提交
    public void btnPostClick(View view){

        //获取Url对象
        new Thread(){
            @Override
            public void run() {
                URL url= null;
                String username=edUserName.getText().toString().trim();
                String password=edPassWord.getText().toString().trim();

                //定义post方式要提交的路径
                final String path="http://192.168.1.64/******";//无需组拼
                try {
                    //定义请求体
                    String data="username="+username+"&password="+password+"";

                    url = new URL(path);
                    //获取HTTPURLConnection对象
                    HttpURLConnection connection=(HttpURLConnection)url.openConnection();
                    //设置Connection访问方式
                    connection.setRequestMethod("POST");
                    //设置超时时间
                    connection.setConnectTimeout(5000);
                    //要多设置两个请求头信息
                    connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
                    connection.setRequestProperty("Content-Length",data.length()+"");

                    //把组拼好的数据提交给服务器
                    connection.setDoInput(true);//设置一个标记允许输出
                    //提交
                    connection.getOutputStream().write(data.getBytes());


                    //获取返回的状态码
                    int code=connection.getResponseCode();
                    //判断状态码
                    if (code==200){
                        //获取流
                        InputStream inputStream=connection.getInputStream();
                        //
                        String content= StreamTool.readStream(inputStream);
                        //将服务器返回的数据返回到Toast里,不能再子线程上更新UI
                        showToast(content);

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }.start();

    }
3.HttpClient方式的get方式提交数据(方法已过时)

sdk6.0以后取消了HttpClient,设置android SDK的编译版本为23时,且使用了httpClient相关类的库项目,会出现有一些类找不到的错误。

解决方法有两种:第一种方法实测可用且为最优解

1.在相应的module下的build.gradle中加入:

useLibrary ‘org.apache.http.legacy’

这条语句一定要加在 android{ } 当中。

如:

android {
useLibrary ‘org.apache.http.legacy’
}

2.将在相应的module下的build.gradle中修改compileSdkVersion的值,设置为更小的sdk版本

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class MainActivity extends AppCompatActivity {
    private EditText edUserName,edPassWord;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initviews();
    }

    public void initviews(){
        edUserName=findViewById(R.id.edUserName);
        edPassWord=findViewById(R.id.edPassWord);
    }
    //Get方式提交
    public void btnGetClick(View view){
        String username=edUserName.getText().toString().trim();
        String password=edPassWord.getText().toString().trim();
        //定义get方式要提交的路径
        final String path="http://192.168.1.64/******username="+username+"&password="+password;
        //获取Url对象
        new Thread(){
            @Override
            public void run() {
                //获取httpClient实例
                DefaultHttpClient client=new DefaultHttpClient();
                //准备get请求,定义一个httpget实现
                HttpGet get=new HttpGet(path);//方法已过时
                //执行一个get请求
                try {
                    HttpResponse response=client.execute(get);
                    //获取服务器返回的状态码
                    int code=response.getStatusLine().getStatusCode();
                    if (code ==200){
                        //获取服务器返回的数据,以流的形式返回
                        InputStream inputStream=response.getEntity().getContent();
                        //把流转换成字符串
                        String content=StreamTool.readStream(inputStream);
                        //显示在控件上
                        showToast(content);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();

    }

    //Post方式提交
    public void btnPostClick(View view){

        //获取Url对象
        new Thread(){
            @Override
            public void run() {

            }
        }.start();

    }

    //封装一个Toast方法,该toast方法执行在主线程当中
    public void showToast(final String content){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //该方法一定执行在主线程的
                Toast.makeText(getApplicationContext(), content, Toast.LENGTH_SHORT).show();
            }
        });
    }

}
3.HttpClient方式的post方式提交数据(方法已过时)
package com.fengray.ex053;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private EditText edUserName,edPassWord;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initviews();
    }

    public void initviews(){
        edUserName=findViewById(R.id.edUserName);
        edPassWord=findViewById(R.id.edPassWord);
    }
    //Get方式提交
    public void btnGetClick(View view){
        String username=edUserName.getText().toString().trim();
        String password=edPassWord.getText().toString().trim();
        //定义get方式要提交的路径
        final String path="http://192.168.1.64/******username="+username+"&password="+password;
        //获取Url对象
        new Thread(){
            @Override
            public void run() {
                //获取httpClient实例
                DefaultHttpClient client=new DefaultHttpClient();
                //准备get请求,定义一个httpget实现
                HttpGet get=new HttpGet(path);//方法已过时
                //执行一个get请求
                try {
                    HttpResponse response=client.execute(get);
                    //获取服务器返回的状态码
                    int code=response.getStatusLine().getStatusCode();
                    if (code ==200){
                        //获取服务器返回的数据,以流的形式返回
                        InputStream inputStream=response.getEntity().getContent();
                        //把流转换成字符串
                        String content=StreamTool.readStream(inputStream);
                        //显示在控件上
                        showToast(content);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();

    }

    //Post方式提交
    public void btnPostClick(View view){

        //获取Url对象
        new Thread(){
            @Override
            public void run() {
                String username=edUserName.getText().toString().trim();
                String password=edPassWord.getText().toString().trim();

                //提交路径
                String path="http://192.168.1.64:8080/login/LoginServlet";
                //以post方式提交
                DefaultHttpClient client = new DefaultHttpClient();
                try {
                    //准备post请求
                    HttpPost post = new HttpPost(path);
                    //准备parameters
                    List<NameValuePair> lists=new ArrayList<>();
                    //准备namevaluepair
                    BasicNameValuePair nameValuePair=new BasicNameValuePair("username",username);
                    BasicNameValuePair pwdValuePair=new BasicNameValuePair("password",password);
                    //把nameValuePair和pwdValuePair加入到集合中去
                    lists.add(nameValuePair);
                    lists.add(pwdValuePair);

                    //准备Entity
                    UrlEncodedFormEntity entity = new UrlEncodedFormEntity(lists);
                    //准备post方式提交的正文,以实体形式提交(键值对形式)
                    post.setEntity(entity);
                    HttpResponse response=client.execute(post);
                    //获取服务器返回的状态码
                    int code=response.getStatusLine().getStatusCode();
                    if (code ==200){
                        //获取服务器返回的数据,以流的形式返回
                        InputStream inputStream=response.getEntity().getContent();
                        //把流转换成字符串
                        String content=StreamTool.readStream(inputStream);
                        //显示在控件上
                        showToast(content);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }


            }
        }.start();

    }

    //封装一个Toast方法,该toast方法执行在主线程当中
    public void showToast(final String content){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //该方法一定执行在主线程的
                Toast.makeText(getApplicationContext(), content, Toast.LENGTH_SHORT).show();
            }
        });
    }

}
4.多线程下载原理(eclipse下实现本例)

多线程下载实现步骤

  • 1、获取文件大小
  • 2、在客户端创建一个大小和服务器一模一样的文件,提前申请好空间
  • 3、每个线程下载的开始位置和结束位置
  • 4、开多个线程去下载
  • 5、知道每个线程什么时候下载完毕了
package com.fengray;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class MultiDownloadMultiDownload {
	//定义下载路径
	static String path="http://swdlcdn.eastmoney.com/swc8_free_new/dfcft8.exe";

	public static void main(String[] args) {
		 // 获取服务器文件大小,计算每个线程的开始位置和结束位置
		
		 URL url;
		try {
			url = new URL(path);
			 //获取HTTPURLConnection对象
	         HttpURLConnection connection=(HttpURLConnection)url.openConnection();
	         //设置Connection访问方式
	         connection.setRequestMethod("GET");
	         //设置超时时间
	         connection.setConnectTimeout(5000);
	         //获取返回的状态码
	         int code=connection.getResponseCode();
	         //判断状态码
	         if (code==200){
	             //获取服务器文件的大小
	        	 int length=connection.getContentLength();
	        	 System.out.println("length:"+length);
	         }
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
	}

}

打印:
length:57764856

4.JAVA实现多线程下载(eclipse下实现本例)
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class MultiDownloadMultiDownload {
	//定义下载路径
	private static String path="http://swdlcdn.eastmoney.com/swc8_free_new/dfcft8.exe";
	//开启线程个数
	private static final int threadCount=3;
	public static void main(String[] args) {
		 // 获取服务器文件大小,计算每个线程的开始位置和结束位置
		
		 URL url;
		try {
			url = new URL(path);
			 //获取HTTPURLConnection对象
	         HttpURLConnection connection=(HttpURLConnection)url.openConnection();
	         //设置Connection访问方式
	         connection.setRequestMethod("GET");
	         //设置超时时间
	         connection.setConnectTimeout(5000);
	         //获取返回的状态码
	         int code=connection.getResponseCode();
	         //判断状态码
	         if (code==200){
	             //获取服务器文件的大小
	        	 int length=connection.getContentLength();
	        	 System.out.println("length:"+length);
	        	 
	        	 //创建一个大小和服务器一模一样的文件,目的是吧空间申请出来
	        	 RandomAccessFile randomAccessFile=new RandomAccessFile("dfcft8.exe", "rw");//可读可写
	        	 randomAccessFile.setLength(length);
	        	 //算出每个线程下载的大小
	        	 int blockSize=length/threadCount;
	        	 //计算每个线程下载的开始和结束位置
	        	 for (int i = 0; i < threadCount; i++) {
	        		 int startIndex=i*blockSize;//每个线程下载的开始位置
	        		 int endIndex=(i+1)*blockSize-1;
	        		 //特殊情况就是最后一个线程
	        		 if(i==threadCount-1) {
	        			 //说明是最后一个线程
	        			 endIndex=length-1;
	        		 }
	        		 
	        		 //开启线程去服务器下载文件
					 DownLoadThread downLoadThread= new DownLoadThread(startIndex, endIndex, i);
					 downLoadThread.start();
				}
	         }
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
	}
	
	//定义线程去服务器下载
	private static class DownLoadThread extends Thread{
		
		private int startIndex,endIndex,threadId;
		//通过构造方法把每个线程的开始位置和结束位置传递过来
		public DownLoadThread(int startIndex,int endIndex,int threadId) {
			this.startIndex=startIndex;
			this.endIndex=endIndex;
			this.threadId=threadId;

		}
		@Override
		public void run() {
			// 实现去服务器下载文件的逻辑
			 
				try {
					 URL url = new URL(path);
					 //获取HTTPURLConnection对象
			         HttpURLConnection connection=(HttpURLConnection)url.openConnection();
			         //设置Connection访问方式
			         connection.setRequestMethod("GET");
			         //设置超时时间
			         connection.setConnectTimeout(5000);
			         
			         //设置一个请求头range(范围)作用是告诉服务器每个线程下载的开始位置和结束位置
			         connection.setRequestProperty("range", "bytes="+startIndex+"-"+endIndex);
			         
			         //获取返回的状态码
			         int code=connection.getResponseCode();
			         //判断状态码
			         if (code==206){//206代表请求的资源成功
			        	 //创建随机读写文件对象
			        	 RandomAccessFile randomAccessFile=new RandomAccessFile("temp.ext", "rw");
			        	 //每个线程要从自己的位置写
			        	 randomAccessFile.seek(startIndex);
			             InputStream inputStream=connection.getInputStream();//这里connection只请求了部分资源
			        	 //把数据写到文件中
			             int len=-1;
			             byte[] buffer=new byte[1024];
			             while ((len=inputStream.read(buffer))!=-1) {
							randomAccessFile.write(buffer,0,len);
						}
			             randomAccessFile.close();
			             System.out.println("线程ID:"+threadId+"----下载完毕");
			         }
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}

	}

}

打印
length:57764856
线程ID:0----下载完毕
线程ID:2----下载完毕
线程ID:1----下载完毕

5.断点续传(eclipse下实现本例)
package com.fengray;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class MultiDownloadMultiDownload {
	//定义下载路径
	private static String path="http://swdlcdn.eastmoney.com/swc8_free_new/dfcft8.exe";
	//开启线程个数
	private static final int threadCount=3;
	public static void main(String[] args) {
		 // 获取服务器文件大小,计算每个线程的开始位置和结束位置
		
		 URL url;
		try {
			url = new URL(path);
			 //获取HTTPURLConnection对象
	         HttpURLConnection connection=(HttpURLConnection)url.openConnection();
	         //设置Connection访问方式
	         connection.setRequestMethod("GET");
	         //设置超时时间
	         connection.setConnectTimeout(5000);
	         //获取返回的状态码
	         int code=connection.getResponseCode();
	         //判断状态码
	         if (code==200){
	             //获取服务器文件的大小
	        	 int length=connection.getContentLength();
	        	 System.out.println("length:"+length);
	        	 
	        	 //创建一个大小和服务器一模一样的文件,目的是吧空间申请出来
	        	 RandomAccessFile randomAccessFile=new RandomAccessFile("dfcft8.exe", "rw");//可读可写
	        	 randomAccessFile.setLength(length);
	        	 //算出每个线程下载的大小
	        	 int blockSize=length/threadCount;
	        	 //计算每个线程下载的开始和结束位置
	        	 for (int i = 0; i < threadCount; i++) {
	        		 int startIndex=i*blockSize;//每个线程下载的开始位置
	        		 int endIndex=(i+1)*blockSize-1;
	        		 //特殊情况就是最后一个线程
	        		 if(i==threadCount-1) {
	        			 //说明是最后一个线程
	        			 endIndex=length-1;
	        		 }
			         System.out.println("当前线程下载的位置为:"+i+"理论下载位置为:"+startIndex+"--"+endIndex);

	        		 //开启线程去服务器下载文件
					 DownLoadThread downLoadThread= new DownLoadThread(startIndex, endIndex, i);
					 downLoadThread.start();
				}
	         }
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
	}
	
	//定义线程去服务器下载
	private static class DownLoadThread extends Thread{
		
		private int startIndex,endIndex,threadId;
		//通过构造方法把每个线程的开始位置和结束位置传递过来
		public DownLoadThread(int startIndex,int endIndex,int threadId) {
			this.startIndex=startIndex;
			this.endIndex=endIndex;
			this.threadId=threadId;

		}
		@Override
		public void run() {
			// 实现去服务器下载文件的逻辑
			 
				try {
					 URL url = new URL(path);
					 //获取HTTPURLConnection对象
			         HttpURLConnection connection=(HttpURLConnection)url.openConnection();
			         //设置Connection访问方式
			         connection.setRequestMethod("GET");
			         //设置超时时间
			         connection.setConnectTimeout(5000);
			         
			         //如果中间断过,继续上次的位置继续下载,从文件中读取上次下载的位置
			         File file=new File(threadId+".txt");
			         if (file.exists() && file.length()>0) {
				         FileInputStream fileInputStream=new FileInputStream(file);
				         BufferedReader br=new BufferedReader(new InputStreamReader(fileInputStream));
				         String lastPosition= br.readLine();	
				         int lastPosi=Integer.parseInt(lastPosition);
				         
				         //要改变一下startIndex的位置
				         startIndex=lastPosi;
				         
				         System.out.println("当前线程下载的位置为:"+threadId+"真实下载位置为:"+startIndex+"--"+endIndex);

				         fileInputStream.close();
				         
					}
			         
			         //设置一个请求头range(范围)作用是告诉服务器每个线程下载的开始位置和结束位置
			         connection.setRequestProperty("range", "bytes="+startIndex+"-"+endIndex);
			         
			         //获取返回的状态码
			         int code=connection.getResponseCode();
			         //判断状态码
			         if (code==206){//206代表请求的资源成功
			        	 //创建随机读写文件对象
			        	 RandomAccessFile randomAccessFile=new RandomAccessFile("temp.txt", "rw");
			        	 //每个线程要从自己的位置写
			        	 randomAccessFile.seek(startIndex);
			             InputStream inputStream=connection.getInputStream();//这里connection只请求了部分资源
			        	 //把数据写到文件中
			             int len=-1;
			             byte[] buffer=new byte[1024];
			             //设置当前线程下载的大小(为给断点续传做准备)
			             int total=0;
			             while ((len=inputStream.read(buffer))!=-1) {
							randomAccessFile.write(buffer,0,len);
							total+=len;
							//实现断点续传,就是把当前线程下载的位置给存起来,下次从此位置下载
							int currentThreadPosition=startIndex+total;//未来将其存在一个普通的txt文本中
							
							//用来存当前线程下载的位置
							RandomAccessFile raff=new RandomAccessFile(threadId+".txt", "rwd");
							raff.write(String.valueOf(currentThreadPosition).getBytes());
							raff.close();
							
						}
			             randomAccessFile.close();
			             System.out.println("线程ID:"+threadId+"----下载完毕");
			         }
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}

	}

}

打印:
length:57764856
当前线程下载的位置为:0理论下载位置为:0–19254951
当前线程下载的位置为:1理论下载位置为:19254952–38509903
当前线程下载的位置为:2理论下载位置为:38509904–57764855
当前线程下载的位置为:2真实下载位置为:57764856–57764855
当前线程下载的位置为:0真实下载位置为:19254952–19254951
当前线程下载的位置为:1真实下载位置为:38509904–38509903

6.断点续传,删除文件(eclipse下实现本例)
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class MultiDownloadMultiDownload {
	//定义下载路径
	private static String path="http://swdlcdn.eastmoney.com/swc8_free_new/dfcft8.exe";
	//开启线程个数
	private static final int threadCount=3;
	//当前正在运行的线程
	private static int runningThread;
	public static void main(String[] args) {
		 // 获取服务器文件大小,计算每个线程的开始位置和结束位置
		
		 URL url;
		try {
			url = new URL(path);
			 //获取HTTPURLConnection对象
	         HttpURLConnection connection=(HttpURLConnection)url.openConnection();
	         //设置Connection访问方式
	         connection.setRequestMethod("GET");
	         //设置超时时间
	         connection.setConnectTimeout(5000);
	         //获取返回的状态码
	         int code=connection.getResponseCode();
	         //判断状态码
	         if (code==200){
	             //获取服务器文件的大小
	        	 int length=connection.getContentLength();
	        	 //把线程数量赋值给正在运行的线程
	        	 runningThread=threadCount;
	        	 
	        	 System.out.println("length:"+length);
	        	 
	        	 //创建一个大小和服务器一模一样的文件,目的是吧空间申请出来
	        	 RandomAccessFile randomAccessFile=new RandomAccessFile(getFileName(path), "rw");//可读可写
	        	 randomAccessFile.setLength(length);
	        	 //算出每个线程下载的大小
	        	 int blockSize=length/threadCount;
	        	 //计算每个线程下载的开始和结束位置
	        	 for (int i = 0; i < threadCount; i++) {
	        		 int startIndex=i*blockSize;//每个线程下载的开始位置
	        		 int endIndex=(i+1)*blockSize-1;
	        		 //特殊情况就是最后一个线程
	        		 if(i==threadCount-1) {
	        			 //说明是最后一个线程
	        			 endIndex=length-1;
	        		 }
			         System.out.println("当前线程下载的位置为:"+i+"理论下载位置为:"+startIndex+"--"+endIndex);

	        		 //开启线程去服务器下载文件
					 DownLoadThread downLoadThread= new DownLoadThread(startIndex, endIndex, i);
					 downLoadThread.start();
				}
	         }
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
	}
	
	//定义线程去服务器下载
	private static class DownLoadThread extends Thread{
		
		private int startIndex,endIndex,threadId;
		//通过构造方法把每个线程的开始位置和结束位置传递过来
		public DownLoadThread(int startIndex,int endIndex,int threadId) {
			this.startIndex=startIndex;
			this.endIndex=endIndex;
			this.threadId=threadId;

		}
		@Override
		public void run() {
			// 实现去服务器下载文件的逻辑
			 
				try {
					 URL url = new URL(path);
					 //获取HTTPURLConnection对象
			         HttpURLConnection connection=(HttpURLConnection)url.openConnection();
			         //设置Connection访问方式
			         connection.setRequestMethod("GET");
			         //设置超时时间
			         connection.setConnectTimeout(5000);
			         
			         //如果中间断过,继续上次的位置继续下载,从文件中读取上次下载的位置
			         File file=new File(getFileName(path)+threadId+".txt");
			         if (file.exists() && file.length()>0) {
				         FileInputStream fileInputStream=new FileInputStream(file);
				         BufferedReader br=new BufferedReader(new InputStreamReader(fileInputStream));
				         String lastPosition= br.readLine();	
				         int lastPosi=Integer.parseInt(lastPosition);
				         
				         //要改变一下startIndex的位置
				         startIndex=lastPosi;
				         
				         System.out.println("当前线程下载的位置为:"+threadId+"真实下载位置为:"+startIndex+"--"+endIndex);

				         fileInputStream.close();
				         
					}
			         
			         //设置一个请求头range(范围)作用是告诉服务器每个线程下载的开始位置和结束位置
			         connection.setRequestProperty("range", "bytes="+startIndex+"-"+endIndex);
			         
			         //获取返回的状态码
			         int code=connection.getResponseCode();
			         //判断状态码
			         if (code==206){//206代表请求的资源成功
			        	 //创建随机读写文件对象
			        	 RandomAccessFile randomAccessFile=new RandomAccessFile(getFileName(path), "rw");
			        	 //每个线程要从自己的位置写
			        	 randomAccessFile.seek(startIndex);
			             InputStream inputStream=connection.getInputStream();//这里connection只请求了部分资源
			        	 //把数据写到文件中
			             int len=-1;
			             byte[] buffer=new byte[1024];
			             //设置当前线程下载的大小(为给断点续传做准备)
			             int total=0;
			             while ((len=inputStream.read(buffer))!=-1) {
							randomAccessFile.write(buffer,0,len);
							total+=len;
							//实现断点续传,就是把当前线程下载的位置给存起来,下次从此位置下载
							int currentThreadPosition=startIndex+total;//未来将其存在一个普通的txt文本中
							
							//用来存当前线程下载的位置
							RandomAccessFile raff=new RandomAccessFile(getFileName(path)+threadId+".txt", "rwd");
							raff.write(String.valueOf(currentThreadPosition).getBytes());
							raff.close();
							
							
						}
			             randomAccessFile.close();
			             System.out.println("线程ID:"+threadId+"----下载完毕");
			             
			             //把txt文件删除,每个线程据悉什么时候下载完毕,我们并不知道
			             synchronized (DownLoadThread.class) {
			            	 runningThread--;
				             if (runningThread==0) {
								//说明所有的线程都执行完毕了,就把.txt文件删除
				            	 for (int i = 0; i < threadCount; i++) {
					            	 File deFile=new File(getFileName(path)+i+".txt");
					            	 deFile.delete();

								}
							}
						}
			             
			         }
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}

	}
	
	public static String getFileName(String path) {
		int start =path.lastIndexOf("/")+1;
		return path.substring(start);
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值