今天偶然想自己实现一下文件上传功能,但又不知从何入手,于是打算走一步算一步。
获得request的输入流,将其完全输出,发现里面的内容格式是类似于这样的:
-----------------------------7d81853a1055a
Content-Disposition: form-data; name="first"
FirstPara
-----------------------------7d81853a1055a
Content-Disposition: form-data; name="file"; filename="C://Documents and Settings//Ray Chase//桌面//Try.txt"
Content-Type: text/plain
TRY
-----------------------------7d81853a1055a
Content-Disposition: form-data; name="last"
LastPara
-----------------------------7d81853a1055a--
其中的双斜杠应该为单斜杠。这样一来我就有思路了:
文件参数之前有个表单参数first,之后有个表单参数last,而分隔这三者的皆是被我称为“分隔符”的东西,即是那个"-----------------------------7d81853a1055a"这样的内容,那么我想我先获取分隔符,然后从那一串filename="......"中获取文件名Try.txt,并从下面一行的Content-Type的后面获取浏览器认定的文件类型,再跳过一个空行,下面就是文件内容了,接着分隔符则标志着文件内容的结束。由此,我就可以依据解析的文件名建立文件,再将对应的文件内容写入了。
那就来尝试一下吧。后来找了几个算法,都有个问题,就是在输入文件内容后总会多加上一个回车换行符(源于request擅自添加的);而我的实现倒是没有这个问题。
package
com.XiongYi.file;
import
java.io.File;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
java.io.InputStream;
import
javax.servlet.ServletException;
import
javax.servlet.ServletInputStream;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
UploadGroupware
extends
HttpServlet
...
{
/** *//**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException ...{
doPost(request,response);
}
/** *//**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException ...{
System.out.println(request.getParameter("first"));
System.out.println(request.getParameter("file"));
//jsp页面中加入了 enctype="multipart/form-data"
//那么这两句话是没有用的,只能输出null。
ServletInputStream sis = request.getInputStream();
byte buf[] = new byte[1024];
int num;
String s;
String type = null;
String pagination = null;
//分隔符。比如:-----------------------------7d83152f30556
while( (num=sis.readLine(buf, 0, buf.length))!=-1 )...{
//readLine的第三个参数和read方法的第三个参数不同,
//read方法第三个参数若为-1表示取到流末尾,
//readLine方法则不能这么用。
if(pagination==null)
pagination = new String(buf,0,num);
s = new String(buf,0,num,"GBK");
if(s.startsWith("Content-Disposition: "))...{
//可能会出现文件
String nextS; //下一行
num = sis.readLine(buf, 0, buf.length);
nextS = new String(buf,0,num,"GBK");
if(!nextS.startsWith("Content-Type: "))
continue; //看来不是文件,继续吧
type = nextS.substring( nextS.indexOf(" ")+1 );
//读取上传文件类型信息
System.out.println(type);
String name = s.substring(s.lastIndexOf("/")+1, s.length()-3);
//取出名字来
System.out.println(name);
File file = new File("./upload/"+name);
FileOutputStream fos = new FileOutputStream(file);
sis.readLine(buf, 0, buf.length); //跳过空行
byte buf2[] = new byte[1024];
//再准备一个相同大小的缓冲数组是为了交替使用,
//以便在发现文件结束时避免输出最末两个字节(回车换行符),
//而这最末的两个字节是request自己加上的!
int num2=0;
boolean whichBuf = true;
//确定使用哪个缓冲数组
while(num!=-1 && num2!=-1)...{
if(whichBuf)...{
num=sis.readLine(buf, 0, buf.length);
s = new String(buf,0,num,"GBK");
if(s.startsWith(pagination))...{
if(num2>=2)
num2 = num2-2;
fos.write(buf2, 0, num2);
num = -1; //写完了
}else...{
fos.write(buf2, 0, num2);
}
}else...{
num2=sis.readLine(buf2, 0, buf2.length);
s = new String(buf2,0,num2,"GBK");
if(s.startsWith(pagination))...{
if(num>=2)
num = num-2;
fos.write(buf, 0, num);
num2 = -1; //写完了
}else...{
fos.write(buf, 0, num);
}
}//else
whichBuf = !whichBuf;
}//while
fos.close();
}//if
}//while
sis.close();
}//doPost
}
经试验上传各种类型的文件(包括图片、文本等)都没有问题。
如果有其他或者优化的方法,请不吝赐教。