码迷,mamicode.com
首页 > 移动开发 > 详细

Android文件的上传和下载

时间:2016-07-22 19:31:34      阅读:266      评论:0      收藏:0      [点我收藏+]

标签:

------------------------------------------------------------------多线程下载操作---------------------------------------------------------------------多线程下载、断点续传,进度可视化。。。


一、---框架---



1、新建一个布局文件,输入我们想要使用的线程的个数,包括一个主布局文件和一个progressBar

(1)一个包括三个控件的主布局

(2)一个只包含ProgressBar的子布局文件

2、找到三个控件,获取该Button控件的点击事件,点击开始下载

(1)获取用户输入线程的个数

(2)清空所有ProgressBar子控件

(3)根据线程数添加相应数量的ProgressBar

(4)在子线程中运行download()函数,因为主线程不能做时间太长的操作

3、进入download()函数,为每个线程设定下载的开始和结束为止

(1)根据url请求网络资源

(2)获取下载资源的大小,并在本地创建占位符

(3)要分配每个线程下载文件的开始位置和结束位置

(4)开启线程去执行下载

4、开启线程下载,需要定义一个线程下载类继承并重写run()方法

(1)通过map获取当前线程对应ProgressBar

(2)建立一个SharedPreferences的操作类用来存取断点信息

(3)设置分段下载的头信息。Range信息:做分段数据请求用的,也就是设置从哪里下载到哪里

(4)请求部分资源成功,开始一边从服务器读取一边写入sdcard

(5)写入过程中将下载进度保存的SharedPreferences中,设置ProgressBar的显示情况



二、---布局创建---



(1)一个包括三个控件的主布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <EditText
        android:id="@+id/et_threadCount"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/bt_download"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="立即下载" />

    <LinearLayout
        android:id="@+id/ll_progress_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
    </LinearLayout>

</LinearLayout>

(2)一个只包含ProgressBar的子布局文件

<?xml version="1.0" encoding="utf-8"?>

<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_height="match_parent" >
</ProgressBar>


(3)初步的界面展示如下

技术分享



三、---点击事件---



如下是一些全局变量的初始化,以及我们在点击“开始下载”之后处理的内容:

(1)定义一些全局变量,这些我们在下面要使用到

public class MainActivity extends Activity implements OnClickListener{

	private EditText et_threadCount;
	private Context mContext;
	private LinearLayout ll_progress_layout;

	private  int threadCount = 0;		//开启3个线程
	private  int blockSize = 0;			//每个线程下载的大小
	private  int runningTrheadCount = 0;//当前运行的线程数
	private  String path = "http://115.25.200.74:8080/itheima74/feiq.exe";
	
	private Map<Integer,ProgressBar> map = new HashMap<Integer, ProgressBar>();

(2)通过布局的ID获取事件

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    mContext = this;
    findViewById(R.id.bt_download).setOnClickListener(this);
    ll_progress_layout = (LinearLayout) findViewById(R.id.ll_progress_layout);
	et_threadCount = (EditText) findViewById(R.id.et_threadCount);
    
}

(3)点击之后添加子控件以及开启下载线程

public void onClick(View v) {
	//获取用户输入的线程数
	String trim = et_threadCount.getText().toString().trim();
	threadCount = Integer.parseInt(trim);

	// 清空所有的子空间
	ll_progress_layout.removeAllViews();
	
	//根据线程数添加相应数量的ProgressBar
	for(int i =0 ;i < threadCount;i++ ){
		ProgressBar progressbar = (ProgressBar)View.inflate(mContext, R.layout.child_progressbar_layout, null);

		map.put(i, progressbar);//将ProgressBar放到map中,方便在线程中获取并设置进度
		//展示progressbar
		ll_progress_layout.addView(progressbar);
	}
	
	new Thread(new Runnable() {

		@Override
		public void run() {
			download();
		}
	}).start();
}


四、---下载位置---


(1)根据url请求网络资源

	//1.请求url地址获取服务端资源的大小
	URL url = new URL(path);
	HttpURLConnection openConnection = (HttpURLConnection) url.openConnection();
	openConnection.setRequestMethod("GET");
	openConnection.setConnectTimeout(10*1000);

(2)获取下载资源的大小,并在本地创建占位符

	int code = openConnection.getResponseCode();
	if(code == 200){
		//获取资源的大小
		int filelength = openConnection.getContentLength();
		//2.在本地创建一个与服务端资源同样大小的一个文件(占位)
		RandomAccessFile randomAccessFile = new RandomAccessFile(new File(getFileName(path)), "rw");
		randomAccessFile.setLength(filelength);//设置随机访问文件的大小

(3)要分配每个线程下载文件的开始位置和结束位置

	//3.要分配每个线程下载文件的开始位置和结束位置。
	blockSize = filelength/threadCount;//计算出每个线程理论下载大小
	for(int threadId =0 ;threadId < threadCount;threadId++){
		int startIndex =  threadId * blockSize;//计算每个线程下载的开始位置
		int endIndex = (threadId+1)*blockSize -1;//计算每个线程下载的结束位置
		//如果是最后一个线程,结束位置需要单独计算
		if(threadId == threadCount-1){
			endIndex = filelength -1;
		}

		//4.开启线程去执行下载
		new DownloadThread(threadId, startIndex, endIndex).start();


五、---开启线程---



(1)基本参数的定义和初始化

	private int threadId;
	private int startIndex;
	private int endIndex;
	private int lastPostion;
	private int currentThreadTotalProgress;
	public DownloadThread(int threadId,int startIndex,int endIndex){
		this.threadId = threadId;
		this.startIndex = startIndex;
		this.endIndex = endIndex;
		// 进度条的最大值
		this.currentThreadTotalProgress = endIndex -startIndex +1;
	}

(2)建立一个SharedPreferences的操作类用来存取断点信息

package com.iigt.download;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

public class SharedUtils {
	
	public static int getLastPosition(Context context,int threadId){
		
		SharedPreferences defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
		return defaultSharedPreferences.getInt("lastPostion"+threadId, -1);		
	}
	
	public static void setLastPosition(Context context,int threadId,int position){
		SharedPreferences defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
		defaultSharedPreferences.edit().putInt("lastPostion"+threadId, position).commit();
	}
}

(3)设置分段下载的头信息。Range信息:做分段数据请求用的,也就是设置从哪里下载到哪里

//分段请求网络连接,分段保存文件到本地
try{
	URL url = new URL(path);
	HttpURLConnection openConnection = (HttpURLConnection) url.openConnection();
	openConnection.setRequestMethod("GET");
	openConnection.setConnectTimeout(10*1000);

	System.out.println("理论上下载:  线程:"+threadId+",开始位置:"+startIndex+";结束位置:"+endIndex);
				
	if(SharedUtils.getLastPosition(mContext, threadId) != -1){				
		
		lastPostion =  SharedUtils.getLastPosition(mContext, threadId);
		
		//说明该线程已经下载完成
		if(lastPostion == endIndex+1){					
			progressBar.setProgress(currentThreadTotalProgress);
			runningTrheadCount = runningTrheadCount -1;						
		}
		
		//设置分段下载的头信息。  Range:做分段数据请求用的。
		openConnection.setRequestProperty("Range", "bytes:"+lastPostion+"-"+endIndex);//bytes:0-500:请求服务器资源中0-500之间的字节信息  501-1000:
		System.out.println("实际下载:  线程:"+threadId+",开始位置:"+lastPostion+";结束位置:"+endIndex);
	}else{

		lastPostion = startIndex;
		//设置分段下载的头信息。  Range:做分段数据请求用的。
		openConnection.setRequestProperty("Range", "bytes:"+lastPostion+"-"+endIndex);
		System.out.println("实际下载:  线程:"+threadId+",开始位置:"+lastPostion+";结束位置:"+endIndex);
	}

(4)请求部分资源成功,开始一边从服务器读取一边写入sdcard

if(openConnection.getResponseCode() == 206){//200:请求全部资源成功, 206代表部分资源请求成功
	InputStream inputStream = openConnection.getInputStream();
	//请求成功将流写入本地文件中,已经创建的占位那个文件中

	RandomAccessFile randomAccessFile = new RandomAccessFile(new File(getFileName(path)), "rw");
	randomAccessFile.seek(lastPostion);//设置随机文件从哪个位置开始写。
	//将流中的数据写入文件
	byte[] buffer = new byte[1024*100];
	int length = -1;
	int total = 0;//记录本次线程下载的总大小

	while((length= inputStream.read(buffer)) !=-1){
		randomAccessFile.write(buffer, 0, length);
		total = total+ length;
		
		//去保存当前线程下载的位置,保存到文件中
		int currentThreadPostion = lastPostion + total;//计算出当前线程本次下载的位置
		SharedUtils.setLastPosition(mContext, threadId, currentThreadPostion);

		//计算线程下载的进度并设置进度
		int currentprogress = currentThreadPostion -startIndex;
		progressBar.setMax(currentThreadTotalProgress);//设置进度条的最大值
		progressBar.setProgress(currentprogress);//设置进度条当前进度


	}
	//关闭相关的流信息
	inputStream.close();
	randomAccessFile.close();

	System.out.println("线程:"+threadId+",下载完毕");

(5)注意下面这两个函数的使用
	public  String getFileName(String url){

		return  Environment.getExternalStorageDirectory() + "/"+ url.substring(url.lastIndexOf("/")+1);

	}

	public String getFilePath(){

		return Environment.getExternalStorageDirectory() + "/";
	}



-----------------------------------------------------------------文件上传操作--------------------------------------------------------------------


一、---框架---



1、客户端上传操作

(1)编写布局文件,一个EditText一个Button

(2)获取输入的文件地址

(3)使用开源Utils做上传操作

2、服务器端接收操作

(1)首先判断上传的数据是表单数据还是带文件的数据 

(2)如果是带文件的数据,在本地创建文件目录

(3)判断文件的类型,表单打印,文件类型就上传



二、---布局创建---



(1)编写布局文件,一个EditText一个Button

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <EditText
        android:id="@+id/et_filepath"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

    <Button
        android:onClick="fileupload"
        android:text="上传"
        android:layout_below="@id/et_filepath"
        android:id="@+id/bt_upload"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>

(2)布局的展示

技术分享



三、---客户端---



(1)获取输入的文件地址

public class MainActivity extends Activity {

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

		
	public void fileupload(View v){
		try{
		EditText et_filepath = (EditText) findViewById(R.id.et_filepath);
		//获取输入的文件地址
		String filepath = et_filepath.getText().toString().trim();

(2)使用开源Utils做上传操作

	//使用开源Utils做上传操作
	AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
	
	RequestParams params = new RequestParams();
	params.put("filename", new File(filepath));
	//url : 请求服务器的url
	asyncHttpClient.post("http://115.25.200.74:8080/itheima74/servlet/UploaderServlet", params, new AsyncHttpResponseHandler() {
		
		@Override
		public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
			if(statusCode == 200){
				Toast.makeText(MainActivity.this, "上传成功", 0).show();
			}
		}
		@Override
		public void onFailure(int statusCode, Header[] headers,
				byte[] responseBody, Throwable error) {
		}
	});
	
	}catch (Exception e) {
		e.printStackTrace();
	}


四、---服务器---



先判断数据类型,接着再判断文件类型,如果是文件的话就上传操作,是表单的话进行打印操作

	public void doGet(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException {

		//首先判断上传的数据是表单数组数据还是一个带文件的数据 
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
		if (isMultipart) {   //如果是true,说明是一个带有文件的数据
			//拿到servlet的真实路径
			String realpath = request.getSession().getServletContext().getRealPath("/files");
			//打印一下路径
			System.out.println("realpath-"+realpath);
			File dir = new File(realpath);
			if (!dir.exists())
				dir.mkdirs(); //如果目标不在就把这个目录给创建出来
			FileItemFactory factory = new DiskFileItemFactory();
			ServletFileUpload upload = new ServletFileUpload(factory); //获得上传文件的对象upload
			upload.setHeaderEncoding("UTF-8");
			try {
				//判断一下上传的数据类型
				List<FileItem> items = upload.parseRequest(request);
				for (FileItem item : items) {
					if (item.isFormField()) { //上传的数据类型是一个表单类型
						String name1 = item.getFieldName();// 得到请求参数的名称
						String value = item.getString("UTF-8");//得到参数值?
						System.out.println(name1 + "=" + value);
					} else {
						//说明这是一个文件类型,进行上传
						item.write(new File(dir, System.currentTimeMillis()
								+ item.getName().substring(item.getName().lastIndexOf("."))));
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
			}
		}
	}


末、---总结---



1、文件的下载操作在安卓2.3上可以正常的使用,但是在安卓4.1上就不能正常运行,由于是刚刚学习,也不知道怎么解决

2、下载中开始开启3个线程,然后中断,再填写5个线程,这时只有最后两个线程运行了



Android文件的上传和下载

标签:

原文地址:http://blog.csdn.net/jinhuoxingkong/article/details/51982828

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!