package org.eh.core.util; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.util.HashMap; import java.util.Map; import org.eh.core.model.FileInfo; /** * 解析content获取上传文件表单信息 * @author 自己写的老有问题,一怒之下copy了一份。不过这个也有些问题,由于office不同版本的Content-Type格式不固定, 所以office文件上传生成的文件一般会少几个字节,以后有心情了再改吧 * @date 2014-3-10 */ public class FileUploadContentAnalysis { static final int NONE = 0; static final int DATAHEADER = 1; static final int FILEDATA = 2; static final int FIELDDATA = 3; static final int MXA_SEGSIZE = 1000 * 1024 * 10; //最大文件长度 public static Map<String, Object> parse(InputStream ins, String contentType, int totalLength) throws IOException { FileInfo fileInfo =new FileInfo(); String fieldname = ""; // 表单域的名称 String fieldvalue = ""; // 表单域的值 String filename = ""; // 文件名 String boundary = ""; // 分界符 String lastboundary = ""; // 结束符 String filefieldname = ""; // 文件表单域名 Map<String, Object> formfields = new HashMap<String, Object>(); int filesize = 0; // 文件长度 int pos = contentType.indexOf("boundary="); if (pos != -1) { // 取得分界符和结束符 pos += "boundary=".length(); boundary = "--" + contentType.substring(pos); lastboundary = boundary + "--"; } int state = NONE; // 得到数据输入流reqbuf DataInputStream in = new DataInputStream(ins); // 将请求消息的实体送到b变量中 int totalBytes = totalLength; if (totalBytes > MXA_SEGSIZE) {// 每批大于10m时 return null; } byte[] b = new byte[totalBytes]; in.readFully(b); in.close(); String reqContent = new String(b, "UTF-8");// BufferedReader reqbuf = new BufferedReader(new StringReader(reqContent)); boolean flag = true; while (flag == true) { String s = reqbuf.readLine(); if ((s == null) || (s.equals(lastboundary))) break; switch (state) { case NONE: if (s.startsWith(boundary)) { state = DATAHEADER; } break; case DATAHEADER: pos = s.indexOf("filename="); if (pos == -1) { // 将表单域的名字解析出来 pos = s.indexOf("name="); pos += "name=".length() + 1; s = s.substring(pos); int l = s.length(); s = s.substring(0, l - 1); fieldname = s; state = FIELDDATA; } else { String temp = s; // 将文件表单参数名解析出来 pos = s.indexOf("name="); pos += "name=".length() + 1; s = s.substring(pos); int pos1 = s.indexOf("\";"); filefieldname = s.substring(0, pos1); // 将文件名解析出来 pos = s.indexOf("filename="); pos += "filename=".length() + 1; s = s.substring(pos); int l = s.length(); s = s.substring(0, l - 1);// 去掉最后那个引号” pos = s.lastIndexOf("\\"); s = s.substring(pos + 1); filename = s; // 从字节数组中取出文件数组 pos = byteIndexOf(b, temp, 0); b = subBytes(b, pos + temp.getBytes().length + 2, b.length);// 去掉前面的部分 int n = 0; /** * 过滤boundary下形如 Content-Disposition: form-data; name="bin"; filename="12.pdf" Content-Type: * application/octet-stream Content-Transfer-Encoding: binary 的字符串 */ while ((s = reqbuf.readLine()) != null) { if (n == 1) break; if (s.equals("")) n++; b = subBytes(b, s.getBytes().length + 2, b.length); } pos = byteIndexOf(b, boundary, 0); if (pos != -1) b = subBytes(b, 0, pos - 1); filesize = b.length - 1; state = FILEDATA; } break; case FIELDDATA: s = reqbuf.readLine(); fieldvalue = s; formfields.put(fieldname, fieldvalue); state = NONE; break; case FILEDATA: while ((!s.startsWith(boundary)) && (!s.startsWith(lastboundary))) { s = reqbuf.readLine(); if (s.startsWith(boundary)) { state = DATAHEADER; break; } } break; } } fileInfo.setFieldname(filefieldname); fileInfo.setBytes(b); fileInfo.setFilename(filename); fileInfo.setLength(filesize); formfields.put(filefieldname, fileInfo); return formfields; } // 字节数组中的INDEXOF函数,与STRING类中的INDEXOF类似 public static int byteIndexOf(byte[] b, String s, int start) { return byteIndexOf(b, s.getBytes(), start); } // 字节数组中的INDEXOF函数,与STRING类中的INDEXOF类似 public static int byteIndexOf(byte[] b, byte[] s, int start) { int i; if (s.length == 0) { return 0; } int max = b.length - s.length; if (max < 0) return -1; if (start > max) return -1; if (start < 0) start = 0; search: for (i = start; i <= max; i++) { if (b[i] == s[0]) { int k = 1; while (k < s.length) { if (b[k + i] != s[k]) { continue search; } k++; } return i; } } return -1; } // 用于从一个字节数组中提取一个字节数组 public static byte[] subBytes(byte[] b, int from, int end) { byte[] result = new byte[end - from]; System.arraycopy(b, from, result, 0, end - from); return result; } // 用于从一个字节数组中提取一个字符串 public static String subBytesString(byte[] b, int from, int end) { return new String(subBytes(b, from, end)); } }