负责上传文件的servlet
package upload;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.Hashtable;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class UploadFileServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
final int NONE = 0; //状态码,标识没有特殊操作
final int DATAHEADER = 1; //标识下一行要读到的抱头信息
final int FILEDATA = 2; //表示下面要读到表单域的文本值
final int FIELDDATA = 3; //表示下面要读的是二进制文件和二进制数据
int totalbytes = request.getContentLength(); //请求消息实体的总长度(请求消息中除了消息头之外的数据长度)
byte[] b = new byte[totalbytes]; //保存请求消息实体的 数组
String contentType = request.getContentType(); //请求消息类型
String fieldname = ""; //表单域的名称
String fieldvalue = "";//表单域的值
String filename = ""; //上传的文件的名字
String boundary = ""; //分界符字符串
String lastBoundary = ""; //结束分界符字符串
int fileSize = 0; //文件长度
Hashtable<String,String> formfields = new Hashtable<String,String>(); //保存表单域的名称/值的哈希表
int pos = contentType.indexOf("boundary="); //在消息头中找到分界符的定义
String fileID; // 上传文件的id
if (pos != -1) {
pos += "boundary=".length();
boundary = "--" + contentType.substring(pos); //解析出分界符
lastBoundary = boundary + "--"; //得到结束分界符
}
int state = NONE; //起始状态是none
DataInputStream in = new DataInputStream(request.getInputStream()); //请求消息的数据输入流
in.readFully(b); //根据长度,将消息实体的内容读入字节数组b中
in.close();
String reqcontent = new String(b);
BufferedReader reqbuf = new BufferedReader(new StringReader(reqcontent));//从字符串中得到输出缓冲流
boolean flag = true; //循环标识
int i = 0;
while (flag == true) {
String s = reqbuf.readLine();
if (s == null || s == lastBoundary)
break;
switch (state) {
case NONE:
if (s.startsWith(boundary)) {
state = DATAHEADER;
i += 1;
}
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; //表单域的名称放入filename
state = FIELDDATA; //设置状态吗,准备读取表单域的值
} else {//如果是文件数据的头,先存储这一行,用于在字节数组中定位
String temp = s;
// 先解析出文件名
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); //定位下一行,2标识一个回车和一个换行站2字节
s = reqbuf.readLine();
File f = new File(filename); //准备文件输入流,准备写文件
DataOutputStream fileout = new DataOutputStream(
new FileOutputStream(f));
b = this.subBytes(b, s.getBytes().length + 4, b.length);
pos = this.byteIndexOf(b, boundary, 0); //定位文件数据的结尾
b = this.subBytes(b, 0, pos - 1); //取得文件数据
fileout.write(b, 0, b.length -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;
} else
break;
}
break;
} // switch
} // while
response.setContentType("text/html;charset=gb2312");//指定内容类型,并且可显示中文
PrintWriter out = response.getWriter();
out
.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>文件上传结果</TITLE></HEAD>");
out.println(" <BODY>");
out.println("<h1>文件上传结果</h1>");
out.println("ID 为" + formfields.get("FileID") + "的文件" + filename
+ "已经上传!" + "文件长度为:" + fileSize + "字节");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
private 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;
}
private static int byteIndexOf(byte[] b, String s, int start) {
return byteIndexOf(b, s.getBytes(), start);
}
private 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;
}
private static String subBytesString(byte[] b,int from,int end){
return new String(subBytes(b,from,end));
}
}
<%@ page language="java" contentType = "text/html;charset=gb2312" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<form method ="POST" action ="UploadFileServlet" enctype ="multipart/form-data">
<p>
I D:
<input type="text" name="FileID" size="20">
</p>
<p>
文件:
<input type="file" name="FileData" size="20">
</p>
<p>
<input type="submit" value="上传" name="uploadfile">
</p>
</form>
</body>
</html>
配置文件web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>UploadFileServlet</servlet-name>
<servlet-class>upload.UploadFileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadFileServlet</servlet-name>
<url-pattern>/UploadFileServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
执行结果:
源码见附件