首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

资料上传的秘密(一)造自己的工具

2012-06-29 
文件上传的秘密(一)造自己的工具RFC1867文档对WEB表单上传文件做了详细的描述,但J2EE的Servlet规范中却没

文件上传的秘密(一)造自己的工具

RFC1867文档对WEB表单上传文件做了详细的描述,但J2EE的Servlet规范中却没有针对此功能规定一个API,没有接口也没有抽象类,更不要说一个具体类了。幸好,著名的开源组织Apache的官网上有一个Common File Upload这个项目,给广大的J2EE开发者解决了这个比较麻烦的问题。会用Common File Upload这个开源组件解决表单文件上传问题是一回事,能知道这个组件的优缺点是另外一回事,如果能知道RFC1867文档中对于表单上传文件的规定、并实现文件上传的功能,是另外一回事。


干嘛干嘛,你这不是闲的蛋疼嘛,有现成的轮子不用,非要再造一个相同的轮子呢?听起来很有道理,可是呢,只能这么说,自行车轮子是不装在汽车上的,福特车的车轮子装不上奥迪车的,为了造出最好的车,就得要亲子动手再造一个最合适的轮子,写软件也是同样的道理。另外,? ?作为一个想成为优秀程序员的人来说,决不会因为使用了Common File Upload而感到自豪。掌握某种技术的原理,并有所创新,才是程序员的王道。本文就是要从零开始,实现文件上传。


好了,废话了这么多,就先看看这个表单上传文件究竟是个什么东东。RFC1867文档规定了HTTP表单上传文件的方式,简明扼要的说,表单的ENCTYPE必须是multipart/form-data,? ?必须是POST方式提交。每个文件的内容经浏览器编码后,使用一个不会和文件内容重复的串把多个文件或者输入域分割开来,这个串叫boundary。为了便于理解RFC1867文档对于文件上传时,浏览器是如何对文件编码的,我们把一个含有文件输入和文本输入的表单,经浏览器编码后,发送到服务器端的请求dump下来,看看究竟。

public class FileUploadParser {private static final String _ENCTYPE = "multipart/form-data";private static final String _FILE_NAME_KEY = "filename";private static final byte[] _CTRF = { 0X0D, 0X0A };private int bufferSize = 0x20000;private byte[] boundary;private HttpServletRequest request;private String dir;private String encoding;public FileUploadParser(HttpServletRequest request, String dir) {this.request = request;this.dir = dir;}        public List<MultiPartFile> parse() throws IOException {List<MultiPartFile> files = new ArrayList<MultiPartFile>();this.parseEnctype();byte[] buffer = new byte[bufferSize];int c = 0;boolean hasFile = false;boolean end = true;while ((c = request.getInputStream().read(buffer)) != -1) {boolean isNewSegment = true;int index = 0;while ((index = BoyerMoore.indexOf(buffer, boundary, index)) != -1) {if (end) {MultiPartFile mpf = parseFile(buffer, index);if (mpf != null) {files.add(mpf);index = mpf.getStart();end = false;hasFile = true;} else {hasFile = false; end = true;index += boundary.length;}} else if (hasFile) {// write buffer to last opening file if current index identifies the start of boundary.// and close the file.MultiPartFile writer = files.get(files.size() - 1);if (isNewSegment) {writer.append(buffer, 0, index - 4);} else {int off = writer.getStart();writer.append(buffer, off, index - off - 4);}writer.close();// start a new parse actionMultiPartFile next = parseFile(buffer, index);if (next != null) {files.add(next);index = next.getStart();end = false;hasFile = true;}else {hasFile = false;end = true;index += boundary.length;}}isNewSegment = false;/* * // create a new MultiPartFile object if found the boundary // * firstly if (files.size() == 0) { MultiPartFile mpf = * parseFile(buffer, index); if (mpf != null) { files.add(mpf); * index = mpf.getStart(); newSegment = false; hasFile = true; * end = false; } else { hasFile = false; continue; // skip next * boundary } } // append the buffer into exists MultiPartFile * object and // then parse next part of content else { * MultiPartFile last = files.get(files.size() - 1); if (hasFile * && newSegment) { last.append(buffer, 0, index - 4); * last.close(); end = true; } else if (hasFile) { int s = * last.getStart(); last.append(buffer, s, index - s - 4); * last.close(); end = true; } else { continue; } newSegment = * false; hasFile = false; index += boundary.length; *  * MultiPartFile next = parseFile(buffer, index); if (next != * null) { files.add(next); index = next.getStart(); hasFile = * true; } else { hasFile = false; continue; // skip next * boundary } } */}// not found boundary, append the buffer into fileif (!end) {MultiPartFile writer = files.get(files.size() - 1);if (isNewSegment) {writer.append(buffer, 0, c);} else {int off = writer.getStart();writer.append(buffer, off, c - off);}}}return files;} ....// 其他辅助函数略?}
?

至此,解析上传文件内容并保存的工作就完成了,但是事情还是没有结束,浏览器在向服务器端发送数据时,会对发送的内容进行编码,这些编码的内容需要一个解码的过程,特别是需要处理中文的web应用。


<原创内容,版权所有,如若转载,请注明出处,不胜感谢!仪山湖>

?

热点排行