转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/23781773html
文件上传是咱们项目中常常使用的功能,通常咱们的服务器可能都是web服务器,当咱们使用非浏览器客户端上传文件时,好比手机(Android)等上传,可能就须要对传输的数据进行规范化的拼接,说白了,就是咱们得本身完成浏览器帮咱们作的事。java
我首先写了服务器端代码,用来接收咱们的数据,一会会贴出源码。而后写了个web页面用于上次,便于咱们看其中的原理。web
当点击了上传之后,这里我使用了firefox的firebug来观察网络信息,能够看到发出了一个POST请求,下面我框出的是请求头信息。里面包含一些请求的配置数据。浏览器
接下来看这张图:服务器
咱们能够看到咱们发送的数据,一个是name为username的普通表单数据,一个为name为uploadFile的一个文件数据,能够看得出来,浏览器把文件数据转化成了2进制而后按特定的格式发给服务器了。网络
好了,下面开始实现上传,模拟浏览器的操做。app
一、使用HttpUrlConnectionsocket
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设置了一系列属性其实就是在设置图二中看到的请求头信息。
因而,咱们完成了请求头的设置,以及须要上传数据的拼接,因此咱们完成了浏览器的工做,天然就实现文件上传了。测试
二、使用Socket实现文件上传,参数基本一致,使用HttpUrlConnection上传有一个很致命的问题就是,当上传文件很大时,会发生内存溢出,手机分配给咱们app的内存更小,因此就更须要解决这个问题,因而咱们可使用Socket模拟POST进行HTTP文件上传。ui
/** * * @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(); }
最后测试咱们的代码:
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(); } }
若是这篇文章对你有帮助,赞一下~