我自己就是一个新手,希望大家能多多指正。
无框架,就是不需要其他组件,如Struts2中文件上传之类的。
流程:
一:提交表单时将form中的enctype属性设为multipart/form-data;
如
二:用getInputStream方法获得上传的数据流,然后用FileOutputStream保存为一个临时文件,用File对象打开该文件;
三:建立一个随机访问文件(RandomAccessFile)读取刚才创建的File对象;
四:用readLine()方式,读取到上传文件的开头;因为上传的数据流里包含了表单的其他信息,以及一些特有的域划分标记(这些内容我并不清楚怎么出来的,可能是内部机制吧)每个请求都有那些数据,因此我只要区分出来,就能取到正确的文件开头,有些文件不用取到正确的文件开头也能打开,但是MD5码却和原来的文件不一样;所以取到正确的文件开头很有必要。还有一点就是取到文件的结尾,如果把<input type="file">放在表单末尾的话,那么文件的结尾就是临时文件的长度-48;这个数字是我反复测试的出来,保存的文件的MD5和原来的一致,说明它们是一样的。下面举例子说明上传的临时文件的结构(有兴趣的可以自己去看看,将数据流保存为一个临时文件,然后用写字板等文本方式打开就能看到)
-------------------4dsf43fffd
xxxxxxxxxxxxx name="xxxx"
asdasd
-------------------4dsf43fffd
XXXXXX name = "bbbb"
ddddff
-------------------4dsf43fffd
xxxxxxxxxxxx name="ccccc" filename="D:\"
xxxx type= xxxxx
asdasdadaasdsad(正确的文件)dsfsdf
sdfsdf
ssdf
sdf
sdf
sdf
sdfsdfsdgdsvx
-------------------4dsf43fffd
大致的结构就是上面的样子;name=是定义的表单的对象,如<input type="text" name="abc"/>
name="abc"就会出现在上面,并且会隔两行到下一个域;当到达文件域时,隔两行刚好是文件的开头;而结尾-48刚好是文件的结尾;因此,我只要用随机访问文件(可以随意定义到文件的任何位置开始读取,可以参看CORE JAVA 第二卷)读取文件开头和结尾之间的内容,就能得到我上传的文件了。
五:用正则判断是否到了文件域,如果到了,读取的该行数据保留下来并解释出文件名,然后读两行;保存文件指针,long start=random.getFilePosition();
六:新建一个File对象f2,用于保存文件,新建一个RandomAccessFile用于把数据保存进f2;从start读到文件结尾,并保存,文件就能正确上传了。
下面是代码
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Index</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<form enctype="multipart/form-data" action="upload.jsp" method="POST">
<select name="toDir">
<option value="all">all</option>
<option value="default" selected="selected">default</option>
</select>
<input type="text" name="Myname" value="Hello" />
文件<input type="file" name="upload" />
<input type="submit" value="提交" />
</form>
</body>
</html>
upload.jsp
<%@ page language="java" import="java.util.*,java.io.*"
pageEncoding="UTF-8"%>
<%@page import="java.util.regex.*"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Upload</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<%
InputStream input = request.getInputStream();//取得上传的数据流
File fi = new File("D:\\uptem");//新建用于保存上传数据流的临时文件
FileOutputStream o = new FileOutputStream(fi);//将数据流保存为文件
int n; //
byte[] b = new byte[1000000]; //设置字节缓冲区
while ((n = input.read(b)) != -1) { //逐个读取
o.write(b, 0, n); //逐个写入
} //
o.close();
RandomAccessFile random = new RandomAccessFile(fi, "r");//随机访问文件只读方式操作保存了的临时文件
String title = "";
String filename = "filename=\"";//正则匹配
Pattern pattern; //正则匹配
Matcher matcher; //
while (true) { //循环读行
title = random.readLine(); //读行,String类型
pattern = Pattern.compile(filename);//匹配内容为filename值
matcher = pattern.matcher(title);//匹配对象为title值
if (matcher.find()) { //有匹配说明已经读到文件域,空读两行到文件开头
filename = title;
title = random.readLine();
title = random.readLine();
out.print(filename);
break;
}
}
long startPosition = random.getFilePointer();//记录文件开头位置;
long endPosition = random.length()-48; //记录文件结束位置;
File f2 = new File("D:\\dom.jar");//新建File用于保存文件,可以自己定义文件名或者解释出来的文件名,这里简略,如果文件名是中文的话,还有编码解码的步骤要进行,否则保存的文件名会不正确
RandomAccessFile random2=new RandomAccessFile(f2,"rw");//新建一个随机访问文件来对保存的文件进行写数据,操作方式为读写rw;
random.seek(startPosition);//定位到文件开头位置,如果前面没有进行读取的话,可以不用定位,因为已经就是文件开头了
while (random.getFilePointer() < endPosition){//循环读取临时文件的部分内容;
n = random.readByte();
random2.write(n); //保存该字节进文件,当所有的字节都保存完时,文件也就能正常使用了;
}
random2.close();//关闭文件,用完就要记得关是好习惯
random.close();
%><br>
</body>
</html>
上面就是一个简单的JSP无框架文件上传,可用于任何文件类型,并且是原样上传。有些地方要注意的是,一:中文名文件的上传,要对文件名进行编解码处理;二:表单中file必须是放在最后,否则,文件结尾并不是我前面的说的长度-48;如果不放在最后可以自己想一些算法,来提取出结尾的正确位置。
参考书籍
1:core java
2:struts2权威指南