文件上传原理
文件上传在很多网站应用中是必不可少的,在 电子商务中上传商品图片,在音乐网站中上传流行 歌曲......一个高效率的文件上传功能尤为重要。 笔 者主要介绍用jsp 方式实现的两个 代码简短又高效率的文件上传功能。
在此基础上,可以对文件上传功能进行进一步的完善,如限制上 传文件的大小, 格式, 指定存放路径,结合数据库 对上传后的文件进行有效的管理等等。在 B/S 模式中,文件上传到服务器的操作分 为:request, 打开request 中的输入流, 生成文件 输出流对象,提取request中上传文件的数据等。
(1)算法设计
在 B/S 模式中, 浏览器 与服务器 是请求 和响应 的 关系。获取来自浏览器端的数据, 主要是通过对 request 进行处理。 文件上传必须使用 post 方式进行数据提交, 文件数据和请求的头部信息被封装在 request中, 被请求执行的服务器端程序通过各种方法对 request 的信息进行处理后, 再执行关键的 I/O 操作。流程图如下:
(2)JSP实现文件上传原理
利用 JSP 内置对象 request 的 getInputStream()方法生成 ServletInputStream类的对象, 即 I/O 中的 输入流对象。
ServletInputStream类提供了 public int readLine(byte[] b,int off,int len) throws java.io.IOException 方法, 该方法按行读取数据, 返回值是实际读取的字节数,request 对象调用 public int getContentLength()返回的请求的字节数,这个值比上传文件的实际大 小要稍大, 因为其中包含了一些附加信息, 比如文 件类型, 文件路径和文件名等,这些附加信息一般 在 200个字节左右, 在限制上传文件大小的时候可以 充分利用该方法。
对输入流中的数据按行读取,不难发现前四行 数据 (上传单个文件时) 正好是附加的信息,例如上传一个静态网页文件,前四行数据如下:
第一行是“boundary” 表示数据开始。第二 行是对数据内容的描述,表单中 file控件的名称以及所上传文件的路径和文件名。第三行是文件类 型。 第四行为一空行。 从第二行数据中取出文件扩 展名后,可以进行上传文件类型的控制, 如上传图 片则判断扩展名是否为.jpg 或.gif 等格式。 需要注意的是, 如果取出的文件路径和文件名值为 空字符串,说明用户没有选择上传的文件,这时候 要进行相应的处理,避免出错。
同时也能看出最后一行也是“boundary” 表 示数据结束。
所上传文件的实际数据从第五行开始,持续到 倒数第二行。 根据这样的特点, 用 ServletInputStream 类的 public int readLine(byte[] b,int off,int len)方法 实现上传功能远远要比使用从InputStream类继承 得到的read(byte[]b) 简单。 从第二行读取文件 名, 这个文件名可作为服务器端保存文件时的文件名。
保存文件的操作通过 FileOutStream 类的 write() 方法实现。在创建该类的对象时, 根据实 际情况指定文件的保存路径。write()方法有多个 型构, 具体选择哪个也很重要。 上传文件一定要保 持文件的大小不改变, 一是要对写进文件的字节数 进行控制!,即实际读取多少数据则写入多少。二要 剔除 request中附加的信息。 因此本方法中使用 write()方法, 文件保存成功后要关闭相应的I/O 流对象, 释放占用的资源。
(3)经典示例
步骤一:静态页面部分(index.jsp)用于选择需要进行 上传的文件
请选择上传的文件步骤二:编辑处理上传页面(upload.jsp)
ServletInputStream in = request.getInputStream();
int len = request.getContentLength();
byte[] b = new byte[len];
int i=0;
i=in.readLine(b,0,b.length);
len-=i;
i=in.readLine(b,0,b.length);
len-=i;
String s = new String(b,0,i);
String fileName = s.substring(s.lastIndexOf("=")+2,s.lastIndexOf("\""));
if("".equals(fileName)){
out.print("");
}else{
String saveName = fileName.substring(fileName.lastIndexOf("\\")+1);
i=in.readLine(b,0,b.length);
len-=i;
i=in.readLine(b,0,b.length);
len-=i;
FileOutputStream fos = new FileOutputStream(request.getRealPath("")+"/"+saveName);
while((i=in.read(b,0, 128))!=-1&&len>47){
len-=i;
fos.write(b,0,i);
}
in.close();
fos.close();
out.print("");
}
%>