java下载文件方案总结以及常见问题分析

背景:前几天总结了文件的上传,本片将从常规下载和多线程下载两个角度去说明如何从网络上下载资源,以及在多线程会遇到的问题和注意点。

1 串行常规下载

思路:1  定位网络资源

            2  打开资源链接

            3 打开资源输出流

           4 利用输入流写如本地文件 

public void downFile(){
		try {
			 URL u=new URL(uri);
			 HttpURLConnection  conn=(HttpURLConnection)u.openConnection();
			 conn.setReadTimeout(5000);
	         conn.setRequestMethod("GET");
	         File f=new File(localFile);
	         RandomAccessFile raf=new RandomAccessFile(f, "rwd");
	         InputStream  is=conn.getInputStream();
	         byte[] buffer=new byte[1024];
	         int len=0;
	         while((len=is.read(buffer)) !=-1 ){
	        	 raf.write(buffer,0,len);
	         }
	         is.close();
	         raf.close();
	         
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

注意点:  1 文件名的获取   2 文件输出流的选择有多种

 

2 多线程下载

思路: 1  定位网络资源

             2 获取文件大小

             3 根据线程数确定每个线程下载的文件大小

             4 多个线程同时去下载

             5 合并或者直接写入文件

class DownThread implements Runnable{
	private String start;
	private String end;
	private String localFile;
	private String uri;
	
	public  DownThread(String uri,String localFile,String start,String end) {
		// TODOr Auto-generated constructor stub
		this.uri=uri;
		this.localFile=localFile;
		this.start=start;
		this.end=end;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			URL u=new URL(uri);
			 HttpURLConnection  conn=(HttpURLConnection)u.openConnection();
			 conn.setReadTimeout(5000);
	         conn.setRequestMethod("GET");
	         conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
	         File f=new File(localFile);
	         RandomAccessFile raf=new RandomAccessFile(f, "rwd");
	         raf.seek(Long.parseLong(start));
	         InputStream  is=conn.getInputStream();
	         byte[] buffer=new byte[1024];
	         int len=0;
	         while((len=is.read(buffer)) !=-1 ){
	        	 raf.write(buffer,0,len);
	         }
	         is.close();
	         raf.close();
	         
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

注意点: 1  多线程文件和网络资源隔离(保证线程安全)  

                2  文件大小获取常规采用 conn.getContentLength()  ,conn.getContentLengthLong(),两种方法获取, 如果返回-1 ,有以下3种情况 :当获取不到的时候可以采用读取head属性Content-Length的方式;还获取不到有可能服务端做了压缩,此处可以发送指令不让服务端压缩connection.setRequestProperty("Accept-Encoding", "identity"),然后根据返回再次获取; 如果还不能凑效,只能统计出chunk之和,那么此时服务端就不支持多线程下载了。

                3  针对每个下载线程发送head头,下载指定的部分 conn.setRequestProperty("Range", "bytes=" + start + "-" + end),有一点需要注意,Range中[start,end]都闭合,所以end最好-1,最后一个线程处理剩余部分。

                4 多线程下载控制写文件有两种方式 : 1 采用随机读取写入文件RandomAccessFile,调用seek(start),定位到写的位置,  2 等所有的线程都返回后顺序写文件(此处需要线程协调控制,join(),CountDownLatch......)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值