zoukankan      html  css  js  c++  java
  • Android入门:文件上传


    文件上传分为两个部分:

    (1)服务器端:需要使用FileUpload+common.io实现文件的上传;

    (2)客户端:需要模拟文件上传的HTTP请求头;



    一、服务器端代码


    FileServlet.java

    package org.xiazdong.servlet;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.List;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    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.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.servlet.ServletFileUpload;
    
    @WebServlet("/FileServlet")
    public class FileServlet extends HttpServlet {
    	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	}
    
    	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		DiskFileItemFactory factory = new DiskFileItemFactory();
    		ServletFileUpload upload = new ServletFileUpload(factory);
    		upload.setFileSizeMax(1024*1024);        				//设置上传文件的最大容量
    		try{
    			List<FileItem>items  = upload.parseRequest(request);  //取得表单全部数据
    			for(FileItem item:items){
    				if(!item.isFormField()){	//如果是上传的文件
    					 String name = "D:\\"+item.getName().substring(item.getName().lastIndexOf('\\')+1);    
    					 String filename = name;
    					 System.out.println(filename);
    				     File f = new File(filename);	//保存到D盘
    				     item.write(f);
    				     System.out.println("上传成功");
    				}
    			}
    		}
    		catch(Exception e){
    			e.printStackTrace();
    		}
    	}
    
    }
    

    浏览器端代码:

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Server Title</title>
    </head>
    <body>
    	<form action="/Server/FileServlet" method="post" enctype="multipart/form-data">
    		文件上传:<input type="file" name="filename"/><br/>
    		<input type="submit" value="get提交">
    	</form>
    </body>
    </html>



    二、客户端前期准备及核心代码


    1.前期准备


    由于客户端需要模拟HTTP请求,因此我们可以先来看下文件上传的HTTP请求:

    POST /Server/FileServlet HTTP/1.1
    Accept: */*
    Referer: http://localhost:8080/Server/2.html
    Accept-Language: zh-CN
    User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0E; .NET4.0C; InfoPath.3)
    Content-Type: multipart/form-data; boundary=---------------------------7dc372520758    //此处为分隔符,用来分隔多个文件和参数
    Accept-Encoding: gzip, deflate
    Host: localhost:8080
    Content-Length: 14610
    Connection: Keep-Alive
    Cache-Control: no-cache


    -----------------------------7dc372520758
    Content-Disposition: form-data; name="filename"; filename="D:\lv6.GIF"
    Content-Type: image/gif
    文件内容
    -----------------------------7dc372520758--   //结束时需要多加两个--

    由此看出,这个HTTP请求比较难以模拟,此处封装了一个辅助类,是黎活明老师实现的,我们可以直接使用:

    HttpRequestUtil.uploadFile(String path, Map<String, String> params, FormFile file)

    path:URL

    params:一般的参数

    file:文件

    HttpRequestUtil.uploadFiles(String path, Map<String, String> params, FormFile[] files)

    path:URL

    params:一般的参数

    files:多个文件


    FormFile.java 

    package com.xiazdong.netword.http.util;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    
    /**
     * 上传文件
     */
    public class FormFile {
    	/* 上传文件的数据 */
    	private byte[] data;
    	private InputStream inStream;
    	private File file;
    	/* 文件名称 */
    	private String filname;
    	/* 请求参数名称*/
    	private String parameterName;
    	/* 内容类型 */
    	private String contentType = "application/octet-stream";
    	
    	/**
    	 * 此函数用来传输小文件
    	 * @param filname
    	 * @param data
    	 * @param parameterName HTML的控件参数名称
    	 * @param contentType
    	 */
    	public FormFile(String filname, byte[] data, String parameterName, String contentType) {
    		this.data = data;
    		this.filname = filname;
    		this.parameterName = parameterName;
    		if(contentType!=null) this.contentType = contentType;
    	}
    	/**
    	 * 此函数用来传输大文件
    	 * @param filname
    	 * @param file
    	 * @param parameterName
    	 * @param contentType
    	 */
    	public FormFile(String filname, File file, String parameterName, String contentType) {
    		this.filname = filname;
    		this.parameterName = parameterName;
    		this.file = file;
    		try {
    			this.inStream = new FileInputStream(file);
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		}
    		if(contentType!=null) this.contentType = contentType;
    	}
    	
    	public File getFile() {
    		return file;
    	}
    
    	public InputStream getInStream() {
    		return inStream;
    	}
    
    	public byte[] getData() {
    		return data;
    	}
    
    	public String getFilname() {
    		return filname;
    	}
    
    	public void setFilname(String filname) {
    		this.filname = filname;
    	}
    
    	public String getParameterName() {
    		return parameterName;
    	}
    
    	public void setParameterName(String parameterName) {
    		this.parameterName = parameterName;
    	}
    
    	public String getContentType() {
    		return contentType;
    	}
    
    	public void setContentType(String contentType) {
    		this.contentType = contentType;
    	}
    	
    }
    


    HttpRequestUtil.java


    package com.xiazdong.netword.http.util;
    
    
    import java.io.BufferedReader;
    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.net.URL;
    import java.net.URLConnection;
    import java.net.URLEncoder;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    
    /*
     * 此类用来发送HTTP请求
     * */
    public class HttpRequestUtil {
    	/**
    	 * 直接通过HTTP协议提交数据到服务器,实现如下面表单提交功能:
    	 *   <FORM METHOD=POST ACTION="http://192.168.0.200:8080/ssi/fileload/test.do" enctype="multipart/form-data">
    			<INPUT TYPE="text" NAME="name">
    			<INPUT TYPE="text" NAME="id">
    			<input type="file" name="imagefile"/>
    		    <input type="file" name="zip"/>
    		 </FORM>
    	 * @param path 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080这样的路径测试)
    	 * @param params 请求参数 key为参数名,value为参数值
    	 * @param file 上传文件
    	 */
    	public static boolean uploadFiles(String path, Map<String, String> params, FormFile[] files) throws Exception{     
            final String BOUNDARY = "---------------------------7da2137580612"; //数据分隔线
            final String endline = "--" + BOUNDARY + "--\r\n";//数据结束标志
            
            int fileDataLength = 0;
            if(files!=null&&files.length!=0){
    	        for(FormFile uploadFile : files){//得到文件类型数据的总长度
    	        	StringBuilder fileExplain = new StringBuilder();
    	 	        fileExplain.append("--");
    	 	        fileExplain.append(BOUNDARY);
    	 	        fileExplain.append("\r\n");
    	 	        fileExplain.append("Content-Disposition: form-data;name=\""+ uploadFile.getParameterName()+"\";filename=\""+ uploadFile.getFilname() + "\"\r\n");
    	 	        fileExplain.append("Content-Type: "+ uploadFile.getContentType()+"\r\n\r\n");
    	 	        fileExplain.append("\r\n");
    	 	        fileDataLength += fileExplain.length();
    	        	if(uploadFile.getInStream()!=null){
    	        		fileDataLength += uploadFile.getFile().length();
    		 	    }else{
    		 	    	fileDataLength += uploadFile.getData().length;
    		 	    }
    	        }
            }
            StringBuilder textEntity = new StringBuilder();
            if(params!=null&&!params.isEmpty()){
    	        for (Map.Entry<String, String> entry : params.entrySet()) {//构造文本类型参数的实体数据
    	            textEntity.append("--");
    	            textEntity.append(BOUNDARY);
    	            textEntity.append("\r\n");
    	            textEntity.append("Content-Disposition: form-data; name=\""+ entry.getKey() + "\"\r\n\r\n");
    	            textEntity.append(entry.getValue());
    	            textEntity.append("\r\n");
    	        }
            }
            //计算传输给服务器的实体数据总长度
            int dataLength = textEntity.toString().getBytes().length + fileDataLength +  endline.getBytes().length;
            
            URL url = new URL(path);
            int port = url.getPort()==-1 ? 80 : url.getPort();
            Socket socket = new Socket(InetAddress.getByName(url.getHost()), port);	       
            OutputStream outStream = socket.getOutputStream();
            //下面完成HTTP请求头的发送
            String requestmethod = "POST "+ url.getPath()+" HTTP/1.1\r\n";
            outStream.write(requestmethod.getBytes());
            String accept = "Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\r\n";
            outStream.write(accept.getBytes());
            String language = "Accept-Language: zh-CN\r\n";
            outStream.write(language.getBytes());
            String contenttype = "Content-Type: multipart/form-data; boundary="+ BOUNDARY+ "\r\n";
            outStream.write(contenttype.getBytes());
            String contentlength = "Content-Length: "+ dataLength + "\r\n";
            outStream.write(contentlength.getBytes());
            String alive = "Connection: Keep-Alive\r\n";
            outStream.write(alive.getBytes());
            String host = "Host: "+ url.getHost() +":"+ port +"\r\n";
            outStream.write(host.getBytes());
            //写完HTTP请求头后根据HTTP协议再写一个回车换行
            outStream.write("\r\n".getBytes());
            //把所有文本类型的实体数据发送出来
            outStream.write(textEntity.toString().getBytes());	       
            //把所有文件类型的实体数据发送出来
            if(files!=null&&files.length!=0){
    	        for(FormFile uploadFile : files){
    	        	StringBuilder fileEntity = new StringBuilder();
    	 	        fileEntity.append("--");
    	 	        fileEntity.append(BOUNDARY);
    	 	        fileEntity.append("\r\n");
    	 	        fileEntity.append("Content-Disposition: form-data;name=\""+ uploadFile.getParameterName()+"\";filename=\""+ uploadFile.getFilname() + "\"\r\n");
    	 	        fileEntity.append("Content-Type: "+ uploadFile.getContentType()+"\r\n\r\n");
    	 	        outStream.write(fileEntity.toString().getBytes());
    	 	        if(uploadFile.getInStream()!=null){
    	 	        	byte[] buffer = new byte[1024];
    	 	        	int len = 0;
    	 	        	while((len = uploadFile.getInStream().read(buffer, 0, 1024))!=-1){
    	 	        		outStream.write(buffer, 0, len);
    	 	        	}
    	 	        	uploadFile.getInStream().close();
    	 	        }else{
    	 	        	outStream.write(uploadFile.getData(), 0, uploadFile.getData().length);
    	 	        }
    	 	        outStream.write("\r\n".getBytes());
    	        }
            }
            //下面发送数据结束标志,表示数据已经结束
            outStream.write(endline.getBytes());
            
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            if(reader.readLine().indexOf("200")==-1){//读取web服务器返回的数据,判断请求码是否为200,如果不是200,代表请求失败
            	return false;
            }
            outStream.flush();
            outStream.close();
            reader.close();
            socket.close();
            return true;
    	}
    	/**
    	 * 提交数据到服务器
    	 * @param path 上传路径(注:避免使用localhost或127.0.0.1这样的路径测试,因为它会指向手机模拟器,你可以使用http://www.itcast.cn或http://192.168.1.10:8080这样的路径测试)
    	 * @param params 请求参数 key为参数名,value为参数值
    	 * @param file 上传文件
    	 */
    	public static boolean uploadFile(String path, Map<String, String> params, FormFile file) throws Exception{
    	   return uploadFiles(path, params, new FormFile[]{file});
    	}
    	/**
    	 * 将输入流转为字节数组
    	 * @param inStream
    	 * @return
    	 * @throws Exception
    	 */
    	public static byte[] read2Byte(InputStream inStream)throws Exception{
    		ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
    		byte[] buffer = new byte[1024];
    		int len = 0;
    		while( (len = inStream.read(buffer)) !=-1 ){
    			outSteam.write(buffer, 0, len);
    		}
    		outSteam.close();
    		inStream.close();
    		return outSteam.toByteArray();
    	}
    	/**
    	 * 将输入流转为字符串
    	 * @param inStream
    	 * @return
    	 * @throws Exception
    	 */
    	public static String read2String(InputStream inStream)throws Exception{
    		ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
    		byte[] buffer = new byte[1024];
    		int len = 0;
    		while( (len = inStream.read(buffer)) !=-1 ){
    			outSteam.write(buffer, 0, len);
    		}
    		outSteam.close();
    		inStream.close();
    		return new String(outSteam.toByteArray(),"UTF-8");
    	}
    }
    



    2.核心代码


    FormFile formFile = new FormFile(file.getName(), file, "document", "text/plain");//"document"为控件的名称,"text/plain"为文件的mimetype
    boolean isSuccess = HttpRequestUtil.uploadFile("http://192.168.0.103:8080/Server/FileServlet", null, formFile);


    三、客户端代码







    AndroidManifest.xml

    	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    	<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    	<uses-permission android:name="android.permission.INTERNET"/>



    MainActivity.java

    package org.xiazdong.network.fileupload;
    
    import java.io.File;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Environment;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;
    
    import com.xiazdong.netword.http.util.FormFile;
    import com.xiazdong.netword.http.util.HttpRequestUtil;
    
    public class MainActivity extends Activity {
    	private EditText fileName;
    	private Button button;
    	private OnClickListener listener = new OnClickListener(){
    		@Override
    		public void onClick(View v) {
    			String fname = fileName.getText().toString();
    			if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)||Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY)){
    				File file = new File(Environment.getExternalStorageDirectory(),fname);	//获得SDCARD的文件
    				if(file.exists()){
    					FormFile formFile = new FormFile(file.getName(), file, "document", "text/plain");
    					try {
    						boolean isSuccess = HttpRequestUtil.uploadFile("http://192.168.0.103:8080/Server/FileServlet", null, formFile);
    						if(isSuccess){
    							Toast.makeText(MainActivity.this, "文件上传成功", Toast.LENGTH_SHORT).show();
    						}
    						else{
    							Toast.makeText(MainActivity.this, "文件上传失败", Toast.LENGTH_SHORT).show();
    						}
    					} catch (Exception e) {
    						e.printStackTrace();
    					}
    				}
    				else{
    					Toast.makeText(MainActivity.this, "文件不存在", Toast.LENGTH_SHORT).show();
    				}
    			}
    			else{
    				Toast.makeText(MainActivity.this, "SDCARD不存在", Toast.LENGTH_SHORT).show();
    			}
    		}
    	};
    	@Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            fileName = (EditText)this.findViewById(R.id.filename);
            button = (Button)this.findViewById(R.id.button);
            button.setOnClickListener(listener);
    	}
    }





  • 相关阅读:
    C语言基础知识-程序流程结构
    C语言基础知识-运算符与表达式
    Cloudera Certified Associate Administrator案例之Configure篇
    Python入门篇-文件操作
    gif软件(ShareX)
    BareTail(日志查看工具)
    [UGUI]游戏中的Tips贴图标边缘显示(贴边)
    Lua中的#
    ugui SetParent在安卓上一个诡异bug
    .svn文件夹特别大
  • 原文地址:https://www.cnblogs.com/xiazdong/p/3058322.html
Copyright © 2011-2022 走看看