android上传大文件到服务器客户端和服务器端代码

使用一般的上传方法一般上传不能超过2m的文件,也非常容易中断和出错,于是本人打算使用xutils框架进行文件上传开发,话不多说直接上源码

首先要下载这个类库的jar包,地址:https://github.com/wyouflf/xUtils

android端代码:

添加权限

 
 


package com.example.download_test;

import java.io.File;

import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.RequestParams;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.http.client.HttpRequest;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class UploadActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_upload);
		
		new Thread(){
			public void run() {
				System.out.println("上传线程启动");
				RequestParams params = new RequestParams();
				params.addHeader("head", "1");
				params.addQueryStringParameter("head", "2");

				// 只包含字符串参数时默认使用BodyParamsEntity,
				// 类似于UrlEncodedFormEntity("application/x-www-form-urlencoded")。
				params.addBodyParameter("222", "22");//相当于与文件同时发给服务器的字符串对象,在servlet中可以通过遍历FileItem的list得到

				// 加入文件参数后默认使用MultipartEntity("multipart/form-data"),
				// 如需"multipart/related",xUtils中提供的MultipartEntity支持设置subType为"related"。
				// 使用params.setBodyEntity(httpEntity)可设置更多类型的HttpEntity(如:
				// MultipartEntity,BodyParamsEntity,FileUploadEntity,InputStreamUploadEntity,StringEntity)。
				// 例如发送json参数:params.setBodyEntity(new StringEntity(jsonStr,charset));
				params.addBodyParameter("file", new File("/storage/emulated/0/Trinea/MeiLiShuo-7.apk"));//设置要上传文件的本地路径,第一个参数就是html中标签中的name属性,是与服务器传输文件字节流以外的文本信息的重要渠道,在servlet中这样获得fileitem.getFieldName();

				HttpUtils http = new HttpUtils();
				http.send(HttpRequest.HttpMethod.POST,
				    "http://192.168.1.112:8080/auto_serve/servlet/UploadImage",//设置要上传到的url
				    params,
				    new RequestCallBack() {

						@Override
						public void onCancelled() {
							// TODO Auto-generated method stub
							super.onCancelled();
							System.out.println("上传终止");
						}

						@Override
						/**
						 * 获取上传进度的方法
						 */
						public void onLoading(long total, long current,//这个方法大约一秒会执行一次
								boolean isUploading) {
							// TODO Auto-generated method stub
							
							System.out.println("目前上传大小"+current+"总大小"+total);
							super.onLoading(total, current, isUploading);
						}

						@Override
						public void onFailure(HttpException arg0, String arg1) {
							// TODO Auto-generated method stub
							System.out.println("android上传失败");
						}

						@Override
						public void onSuccess(ResponseInfo arg0) {
							// TODO Auto-generated method stub
							System.out.println("android上传成功");
						}

				      

				     
				});
				
			};
		}.start();
	}

	
}

如果想要添加一个带进度条的对话框,可以在onLoading方法中更新进度条进度,如下

@Override  
                     /** 
                      * 获取上传进度的方法 
                      */  
                     public void onLoading(long total, long current,//这个方法大约一秒会执行一次  
                             boolean isUploading) {  
                         // TODO Auto-generated method stub  
                           
                         System.out.println("目前上传大小"+current+"总大小"+total); 
                         int process = 0;
                        try {
                            process = (int) (current/(total/100));
                        } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                         Message message = Message.obtain();
                         message.arg1 = process;
                         handler.sendMessage(message);
                         
                     }  
 
class upLoadHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            if(msg.arg1>0)
            mReadProcessDia.setProgress(msg.arg1);
        }
    }

//release是发布按钮Button
release.setOnClickListener(new OnClickListener() {
								
								@Override
								public void onClick(View v) {
									// TODO Auto-generated method stub
								mReadProcessDia=new ProgressDialog(IndexActivity.this);  
							        mReadProcessDia.setProgress(0);  
							        mReadProcessDia.setIndeterminate(false);  
							        mReadProcessDia.setCancelable(false);//设置进度条对话框是否可以被点没,如果为true,相当于后台下载,完毕后不受影响
							        mReadProcessDia.setTitle("上传进度");  
							        mReadProcessDia.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);  
							        mReadProcessDia.setMax(100);  
							        mReadProcessDia.show();  
							        new Thread(runnable).start();
								}
							});


如果要从相册选择一张图片,并且显示在imageView上,有如下代码

//commentPic是个添加图片的按钮
commentPic.setOnClickListener(new OnClickListener() {//点击一下打开相册,从相册获取一个图片的uri
					  
						@Override
						public void onClick(View v) {
							// TODO Auto-generated method stub
							Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);  
							intent.setType("image/*");    //这个参数是确定要选择的内容为图片,
							intent.putExtra("return-data", true);  //是否要返回值。 一般都要。我第一次忘加了,总是取得空值,囧!
							Activity activity = (Activity) context;//获得一个上下文
							activity.startActivityForResult(intent, 2);

						}
					});
					  
					  commentView = (ImageView) popupView.findViewById(R.id.commentView);

//在Activity的onActivityResult方法接受相册选取结果uri
@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        // TODO Auto-generated method stub
        super.onActivityResult(requestCode, resultCode, data);   
        System.out.println("数据传回了");
        if (resultCode == -1) {  
                    System.out.println("requestCode"+requestCode);  
                 if (requestCode == 2) {  //之前intent设置的自定义码是2
                           Uri uri = data.getData();  //接受相册返回的uri
                          ImageView imageView = TuijianAdapter.commentView;//获取要显示图片的imageView
                           System.out.println("Uri是"+uri.getPath());  
                          System.out.println("真实路径是"+ getRealPathFromURI(this,uri));//从一个uri获取file指针的方法,获取file指针是为了上传
                           ContentResolver cr = getContentResolver();  
                          file = new File(getRealPathFromURI(this,uri));//从一个uri获取file指针的方法
                          System.out.println("图像大小是"+file.length());//检测图像是否加载成功,并判断是否超大
                           try {  
                               Bitmap bmp = BitmapFactory.decodeStream(cr.openInputStream(uri));//把一个uri转换成字节流输入,并显示到imageView
                               imageView.setImageBitmap(bmp);
                               imageView.setVisibility(View.VISIBLE);
                              
                           } catch (FileNotFoundException e) {  
                            // TODO Auto-generated catch block  
                            e.printStackTrace();  
                           }  
                          
                } else {
                    System.out.println("修建失败");
                }
     } else {
        System.out.println("选择失败");
    }






tomcat服务器servlet端代码,需要导入apache的commons-io和commons-lang包

package com.situ.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.RandomStringUtils;


public class UploadImage extends HttpServlet {

	/**
	 * The doGet method of the servlet. 
* * This method is called when a form has its tag value method equals to get. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println(""); out.println(""); out.println(" A Servlet"); out.println(" "); out.print(" This is "); out.print(this.getClass()); out.println(", using the GET method"); out.println(" "); out.println(""); out.flush(); out.close(); } /** * The doPost method of the servlet.
* * This method is called when a form has its tag value method equals to post. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("收到上传请求"); //获得磁盘文件条目工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); //获取文件缓存文件夹的路径 String tempPath = request.getRealPath("/temp"); System.out.println("path为"+tempPath); //C:\apache-tomcat-7.0.61/webapps/auto_serve/upload String path2 = request.getContextPath(); System.out.println("contextPath为"+path2);//:/auto_serve //如果没以下两行设置的话,上传大的 文件 会占用 很多内存, //设置暂时存放的 存储室 , 这个存储室,可以和 最终存储文件 的目录不同 /** * 原理 它是先存到 暂时存储室,然后在真正写到 对应目录的硬盘上, * 按理来说 当上传一个文件时,其实是上传了两份,第一个是以 .tem 格式的 * 然后再将其真正写到 对应目录的硬盘上 */ File tempFolder = new File(tempPath); if(tempFolder.exists()==false){ tempFolder.mkdirs(); } //设置缓存文件夹 factory.setRepository(tempFolder); //设置 缓存的大小,当上传文件的容量超过该缓存时,直接放到 暂时存储室 factory.setSizeThreshold(1024*1024) ; //大文件的上传处理 ServletFileUpload upload = new ServletFileUpload(factory); List list = null; try { list = (List)upload.parseRequest(request); System.out.println("上传文件的数量是"+list.size()); } catch (FileUploadException e) { // TODO Auto-generated catch block e.printStackTrace(); } for(FileItem item : list) { //获取表单的属性名字 String name = item.getFieldName(); //这个name就是标签中的name属性,是很重要与服务器通信的方式 System.out.println("传来的filedName是"+name); //如果获取的 表单信息是普通的 文本 信息 if(item.isFormField()) { System.out.println("传来一个文本"); System.out.println(item); } //对传入的非 简单的字符串进行处理 ,比如说二进制的 图片,电影这些 else { System.out.println("传来一个文件"); /** * 以下三步,主要获取 上传文件的名字 */ //获取路径名 String value = item.getName() ; //索引到最后一个反斜杠 int start = value.lastIndexOf("\\"); //截取 上传文件的 原来的名字,加1是 去掉反斜杠, String filename = value.substring(start+1); //虽然上面已经获取了文件原本的名字,但是服务器一般用随机数命名 String randomName = RandomStringUtils.random(10);//用apche commons-long包中的类生成随机字符串 //将文件写入服务器,第二个参数是文件名(不加扩展名),第三个参数是要写入的文件夹 writeFile(item, randomName, "item_imgs"); } } PrintWriter out = response.getWriter(); out.print("{}");//返回空json字符串代表上传成功,同时在浏览器收到后会出现绿色的对勾,如果失败就传输一个"{error:'错误信息'}",这样的话进图条就走不到100%并且还会锁死 out.flush(); out.close(); } /** * 传入一个fileitem,并且按照给出的文件名前缀,文件名后缀(索引),文件存储相对目录来写入从互联网的到的文件 * @param fileItem 传来的文件对象 * @param firstName 文件名前缀 * @param parentFolder 相对存储目录,如:"imgs" 根目录C:\apache-tomcat-7.0.61\webapps\项目名\+parentFolder\ * @return * @throws IOException */ public boolean writeFile(FileItem fileItem,String firstName,String parentFolder) throws IOException{ //用原来的文件名做文件名,用项目目录的绝对地址/attachment作为目录地址 File file1 = new File(this.getServletContext().getRealPath(parentFolder+"/"),firstName); if(file1.getParentFile().exists()==false){ file1.getParentFile().mkdirs(); } file1.createNewFile(); InputStream ins = fileItem.getInputStream(); OutputStream ous = new FileOutputStream(file1); try{ byte[] buffer = new byte[1024]; System.out.println("开始写文件"); int len = 0; while((len = ins.read(buffer)) > -1) ous.write(buffer,0,len); System.out.println("已保存的文件"+file1.getAbsolutePath()); }finally{ ous.close(); ins.close(); } return true; } }


本servlet服务器端代码同样适用于html的文件上传表单,详细请参考本人另一篇博文《 bootstrap3 文件上传插件fileinput中文说明文档》


你可能感兴趣的:(android上传大文件到服务器客户端和服务器端代码)