`
jgsj
  • 浏览: 1028242 次
文章分类
社区版块
存档分类
最新评论

从原理角度解析Android (Java) http 文件上传

 
阅读更多

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/23781773

文件上传是我们项目中经常使用的功能,一般我们的服务器可能都是web服务器,当我们使用非浏览器客户端上传文件时,比如手机(Android)等上传,可能就需要对传输的数据进行规范化的拼接,说白了,就是我们得自己完成浏览器帮我们做的事。

我首先写了服务器端代码,用来接收我们的数据,一会会贴出源码。然后写了个web页面用于上次,便于我们看其中的原理。


当点击了上传以后,这里我使用了firefox的firebug来观察网络信息,可以看到发出了一个POST请求,下面我框出的是请求头信息。里面包含一些请求的配置数据。


接下来看这张图:

我们可以看到我们发送的数据,一个是name为username的普通表单数据,一个为name为uploadFile的一个文件数据,可以看得出来,浏览器把文件数据转化成了2进制然后按特定的格式发给服务器了。


好了,下面开始实现上传,模拟浏览器的操作。

1、使用HttpUrlConnection

private static final String BOUNDARY = "----WebKitFormBoundaryT1HoybnYeFOGFlBR";

	/**
	 * 
	 * @param params
	 *            传递的普通参数
	 * @param uploadFile
	 *            需要上传的文件名
	 * @param fileFormName
	 *            需要上传文件表单中的名字
	 * @param newFileName
	 *            上传的文件名称,不填写将为uploadFile的名称
	 * @param urlStr
	 *            上传的服务器的路径
	 * @throws IOException
	 */
	public void uploadForm(Map<String, String> params, String fileFormName,
			File uploadFile, String newFileName, String urlStr)
			throws IOException {
		if (newFileName == null || newFileName.trim().equals("")) {
			newFileName = uploadFile.getName();
		}

		StringBuilder sb = new StringBuilder();
		/**
		 * 普通的表单数据
		 */
		for (String key : params.keySet()) {
			sb.append("--" + BOUNDARY + "\r\n");
			sb.append("Content-Disposition: form-data; name=\"" + key + "\""
					+ "\r\n");
			sb.append("\r\n");
			sb.append(params.get(key) + "\r\n");
		}
		/**
		 * 上传文件的头
		 */
		sb.append("--" + BOUNDARY + "\r\n");
		sb.append("Content-Disposition: form-data; name=\"" + fileFormName
				+ "\"; filename=\"" + newFileName + "\"" + "\r\n");
		sb.append("Content-Type: image/jpeg" + "\r\n");// 如果服务器端有文件类型的校验,必须明确指定ContentType
		sb.append("\r\n");

		byte[] headerInfo = sb.toString().getBytes("UTF-8");
		byte[] endInfo = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("UTF-8");
		System.out.println(sb.toString());
		URL url = new URL(urlStr);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setRequestMethod("POST");
		conn.setRequestProperty("Content-Type",
				"multipart/form-data; boundary=" + BOUNDARY);
		conn.setRequestProperty("Content-Length", String
				.valueOf(headerInfo.length + uploadFile.length()
						+ endInfo.length));
		conn.setDoOutput(true);

		OutputStream out = conn.getOutputStream();
		InputStream in = new FileInputStream(uploadFile);
		out.write(headerInfo);

		byte[] buf = new byte[1024];
		int len;
		while ((len = in.read(buf)) != -1)
			out.write(buf, 0, len);

		out.write(endInfo);
		in.close();
		out.close();
		if (conn.getResponseCode() == 200) {
			System.out.println("上传成功");
		}

	}
我详细解释一下,首先我拼接了需要发送的数据,其实就是咱们在图三中看到的数据,然后使用HttpUrlConnetion设置了一系列属性其实就是在设置图二中看到的请求头信息。

于是,我们完成了请求头的设置,以及需要上传数据的拼接,所以我们完成了浏览器的工作,自然就实现文件上传了。

2、使用Socket实现文件上传,参数基本一致,使用HttpUrlConnection上传有一个很致命的问题就是,当上传文件很大时,会发生内存溢出,手机分配给我们app的内存更小,所以就更需要解决这个问题,于是我们可以使用Socket模拟POST进行HTTP文件上传。

	/**
	 * 
	 * @param params
	 *            传递的普通参数
	 * @param uploadFile
	 *            需要上传的文件名
	 * @param fileFormName
	 *            需要上传文件表单中的名字
	 * @param newFileName
	 *            上传的文件名称,不填写将为uploadFile的名称
	 * @param urlStr
	 *            上传的服务器的路径
	 * @throws IOException
	 */
	public void uploadFromBySocket(Map<String, String> params,
			String fileFormName, File uploadFile, String newFileName,
			String urlStr) throws IOException {
		if (newFileName == null || newFileName.trim().equals("")) {
			newFileName = uploadFile.getName();
		}

		StringBuilder sb = new StringBuilder();
		/**
		 * 普通的表单数据
		 */

		if (params != null)
			for (String key : params.keySet()) {
				sb.append("--" + BOUNDARY + "\r\n");
				sb.append("Content-Disposition: form-data; name=\"" + key
						+ "\"" + "\r\n");
				sb.append("\r\n");
				sb.append(params.get(key) + "\r\n");
			}                                                                                                                                                  else{ab.append("\r\n");}
		/**
		 * 上传文件的头
		 */
		sb.append("--" + BOUNDARY + "\r\n");
		sb.append("Content-Disposition: form-data; name=\"" + fileFormName
				+ "\"; filename=\"" + newFileName + "\"" + "\r\n");
		sb.append("Content-Type: image/jpeg" + "\r\n");// 如果服务器端有文件类型的校验,必须明确指定ContentType
		sb.append("\r\n");

		byte[] headerInfo = sb.toString().getBytes("UTF-8");
		byte[] endInfo = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("UTF-8");

		System.out.println(sb.toString());

		URL url = new URL(urlStr);
		Socket socket = new Socket(url.getHost(), url.getPort());
		OutputStream os = socket.getOutputStream();
		PrintStream ps = new PrintStream(os, true, "UTF-8");

		// 写出请求头
		ps.println("POST " + urlStr + " HTTP/1.1");
		ps.println("Content-Type: multipart/form-data; boundary=" + BOUNDARY);
		ps.println("Content-Length: "
				+ String.valueOf(headerInfo.length + uploadFile.length()
						+ endInfo.length));
		ps.println("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");

		InputStream in = new FileInputStream(uploadFile);
		// 写出数据
		os.write(headerInfo);

		byte[] buf = new byte[1024];
		int len;
		while ((len = in.read(buf)) != -1)
			os.write(buf, 0, len);

		os.write(endInfo);

		in.close();
		os.close();
	}

这里因为我们使用的是Socket,所以自然对于请求头,我们也需要自己拼接了,没有什么属性设置了。参考图二框出的部分,我们使用PrintStream完成了请求头的拼接,接下来就是数据的拼接,这和使用HttpUrlConnection的方式一致。我们也完成了数据的上传。

最后测试我们的代码:

public static void main(String[] args) {
		try {
			
			File file = new File("D:/dtd", "dwr30.dtd");

			new Test().uploadForm(null, "uploadFile", file, "helloworld.txt",
					"http://localhost:8080/strurts2fileupload/uploadAction");

			new Test().uploadFromBySocket(null, "uploadFile", file,
					"hibernate-configuration-3.0.dtd",
					"http://localhost:8080/strurts2fileupload/uploadAction");

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

效果:




如果这篇文章对你有帮助,赞一下~


源码点击此处下载




分享到:
评论

相关推荐

    shp文件解析java实现

    本篇文章将详细讲解如何使用`meteoInfo`和`geotools`这两个Java库来解析`shp`文件,提取其中的数据,并获取边界线数据、中心点坐标以及最大和最小经纬度值。 `meteoInfo`是一个专门处理气象数据的Java库,虽然它的...

    java解析PDF文件

    java解析PDF格式的文件demo。JAVA实现PDF解析,对PDF文件中的文本内容可输出仅供参考学习,不喜勿喷。

    java解析上传的shp文件,包含jar,方法,shp文件

    在Java编程环境中,解析Shapefile(.shp)文件是一项常见的任务,特别是在地理信息系统(GIS)应用中。Shapefile是一种广泛用于存储地理空间数据的开放格式。为了在Java中处理这些文件,我们可以利用开源库GeoTools...

    Android解析midi文件

    本教程将深入探讨如何在Android中解析MIDI文件,通过Java编程语言实现。 首先,我们需要了解MIDI文件的基本结构。MIDI文件由一系列事件组成,包括音符开始、音符结束、控制器变化等。这些事件被组织在称为“轨道”...

    JAVA文件上传原理源代码

    纯java代码,演示上传文件,适合任何文件,主要是了解HTTP请求的信息,然后解析请求的字符串,此事例只考虑了现在的两种主要的浏览器的请求,因为浏览器不一样文件名会有差异,IE就只有文件名,而FF就是全路径名

    java对mht文件解析

    ### Java对MHT文件解析及内容抓取技术详解 #### 一、引言 MHT(Mime HTML)文件是一种将HTML文档与嵌入资源(如图像、样式表等)合并为一个文件的格式,方便在网络上传输。本文将详细介绍如何使用Java语言解析MHT...

    Android-Java代码解析class文件

    总结来说,理解并解析Java的class文件对于Android开发者来说非常重要,这不仅能帮助我们优化代码、排查问题,还能增强对代码底层运行机制的理解,从而编写出更高效、更安全的应用。通过学习和使用相关工具,开发者...

    Java实现解析dcm医学影像文件并提取文件信息的方法示例

    Java实现解析dcm医学影像文件并提取文件信息的方法示例 本文主要介绍了Java实现解析dcm医学影像文件并提取文件信息的方法,结合实例形式分析了Java基于第三方库文件针对dcm医学影像文件的解析操作相关实现技巧。...

    java解析DWG文件为json使用superMap

    【标题】:“java解析DWG文件为json使用superMap” 【描述】:“java使用superMap解析DWG文件为json输出,本地通过,附件中为word操方式按照步骤可以导入数据集” 【标签】:“java解析DWG文件json java读取dwg...

    Java解析FTP服务器文本文件

    Java解析FTP服务器文本文件是指使用Java语言连接FTP服务器,上传、下载、递归目录遍历等基本操作的集合。在这个过程中,我们需要引入相关的jar包,例如cpdetector.jar、jchardet-1.0.jar、antlr.jar、commons-...

    java 解析 chm 文件

    Java解析CHM文件是将Microsoft的 Compiled HTML Help (CHM) 文件转换成HTML网页的过程。CHM文件是一种常见的帮助文档格式,它包含了多个HTML页面、图像和其他资源,并使用了一种特殊的压缩方法存储。在Java中处理CHM...

    Java解析SO(ELF)文件

    本篇文章将详细探讨如何使用Java来解析SO(ELF)文件,包括文件头部、程序头部表和节区头部表等关键组成部分。 首先,我们需要理解ELF文件格式的基本概念。ELF是一种广泛使用的Unix和类Unix系统中的可执行文件、...

    Java读取解析GRIB2文件

    下面将详细介绍如何使用Java进行GRIB2文件的读取和解析。 1. **理解GRIB2文件结构**: GRIB2文件由多个消息组成,每个消息包含一组相关的气象数据。消息由一个固定长度的头部(Header)和可变长度的数据部分(Data...

    Java解析apk文件

    本篇文章将深入探讨如何使用Java解析APK文件,提取其中的关键信息,包括版本号码、版本名称、包名、权限、最低支持的Android平台版本、SDK版本以及应用程序的相关元数据。 首先,我们需要了解APK文件的结构。APK是...

    java解析apk/ipa文件的信息

    Java作为一种跨平台的编程语言,提供了多种工具和方法来解析这些文件,以获取应用的相关信息。下面我们将详细探讨如何在Windows平台上使用Java进行APK和IPA文件的解析。 首先,解析APK文件通常涉及到以下几个步骤:...

    java Swing 上传文件

    java Swing 上传文件-------------------------------------------------------------------------------------------------------------------------------------------------------

    java按行读取大文件并解析入库

    为了高效地处理这类问题,我们可以利用Java的`java.nio`包中的BufferedReader和FileChannel等类,实现按行读取大文件,并将其内容解析后存储到数据库中。本文将详细讲解这一过程。 首先,我们需要了解`java.nio`包...

    java、Android实现Excel表的解析读取操作

    在IT行业中,尤其是在数据处理和应用开发领域...通过以上方法,你可以在Java和Android环境中有效地解析和读取Excel文件,满足数据处理的需求。无论是简单的数据展示还是复杂的业务逻辑,都能游刃有余地处理Excel数据。

    EPUB 解析 (java)

    首先,解析过程通常从读取OPF(Open Packaging Format)文件开始,这是一个XML文件,包含了关于EPUB包的所有元数据,如书名、作者、出版社等,以及文件的内部结构。通过DOM(Document Object Model)或SAX(Simple ...

    java实现大文件上传并有进度条及其代码解析

    本文将详细介绍如何使用Java实现大文件的上传并展示进度条,同时解析相关的代码实现。 1. **大文件分块上传** 大文件上传的关键在于避免一次性加载整个文件到内存,因为这可能导致内存溢出。Java中,我们可以使用`...

Global site tag (gtag.js) - Google Analytics