java上传原理
文件的上传在本地来说就是把一个文件挪到另一个地方,对于网络来说只是目标地址是网络的地址而已。java实现的原理代码如下:
File source =new File("F:/music/一生爱你千百回.mp3");
//定义目标路径
File target =new File("D:/music",source.getName());
//开始上传
CopyFile(source,target);
//实现文件上传的核心代码
static void CopyFile (File source ,File target){
InputStream in=null;
OutputStream out=null;
in=new FileInputStream(source);
out=new FileOutputStream(target);
byte[] buf =new byte[1024*10];
int len=in.read(buf);
while(len!=-1){
out.write(buf,0,len);
len=in.read(buf);
}
}
============================================================================
下面就是手工写的一个servlet上传的一个例子:
1:控制层的代码:ServletActon.jsp
package com.test.action;
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 ServletAction extends HttpServlet{
??? @Override
??? protected void doGet(HttpServletRequest request, HttpServletResponse response)
??? ??? ??? throws ServletException, IOException {
??? ??? doPost(request,response);
??? }
??? @Override
??? protected 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;
??? ??? //将请求消息的实体送到b变量中
??? ??? 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 formfields=new Hashtable();
??? ??? int pos=contentType.indexOf("boundary=");
??? ??? String fileID;? //上传的文件ID
??? ??? if(pos!=-1)???? //取得分界符和结束符
??? ??? {
??? ????? pos+="boundary=".length();
??? ????? boundary="--"+contentType.substring(pos);
??? ????? lastboundary=boundary+"--";
??? ??? }
??? ??? int state=NONE;
??? ??? //得到数据输入流reqbuf
??? ??? DataInputStream in=new DataInputStream(request.getInputStream());
??? ??? in.readFully(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==lastboundary)||(s==null)) 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;
??? ????????????? 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);//去掉前面的部分
??? ????????????? s=reqbuf.readLine();
??? ????????????? b=subBytes(b,s.getBytes().length+4,b.length);
??? ????????????? pos=byteIndexOf(b,boundary,0);
??? ????????????? b=subBytes(b,0,pos-1);
??? ????????????? File f=new File(formfields.get("FilePath")+"\"+filename);? //写入文件
??? ????????????? DataOutputStream fileout=new DataOutputStream(new FileOutputStream(f));
??? ????????????? 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;
??? ????????????????? break;
??? ?????????????? }
??? ??????????? }
??? ??????????? break;
??? ????? }
??? ??? }
??? ??? //指定输出类型
??? ??? response.setContentType("text/html;charset=gb2312");
??? ??? PrintWriter out =response.getWriter();
??? ??? out.println("<html>");
??? ??? out.println("<head><title>文件上传结果</title></head>");
??? ??? out.println("<body>");
??? ??? out.println("<h1>文件上传结果</h1><hr>");
??? ??? out.println("ID为"+formfields.get("FileID")+"的文件"+filename+"已经上传!"+
??? ??????????????? "文件长度为:"+filesize+"字节");
??? ??? out.println("</body></html>");
??? ??? out.close();
??? ???
??? }
???
??? ?//Get Servlet information
??? ? public String getServletInfo() {
??? ??? return "UploadServlet.UploadServlet Information";
??? ? }
??? ?
??? ? //字节数组中的INDEXOF函数,与STRING类中的INDEXOF类似
??? ? private static int byteIndexOf(byte[] b,String s,int start)
??? ? {
??? ????? return byteIndexOf(b,s.getBytes(),start);
??? ? }
??? ?
??? ? //字节数组中的INDEXOF函数,与STRING类中的INDEXOF类似
??? ? 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 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 String subBytesString(byte[] b,int from,int end)
??? ?{
??? ?? return new String(subBytes(b,from,end));
??? ?}
}
2:客户端的代码 index.html
?
<html>
?
<head>
<meta http-equiv="Content-Language" content="zh-cn">
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>上传文件</title>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse"
? bordercolor="#111111" width="100%" id="AutoNumber1">
? <tr>
??? <td width="15%"> </td>
??? <td width="80%">
??? <table border="0" cellpadding="10" cellspacing="10" style="border-collapse: collapse"
?????? bordercolor="#111111" width="100%" id="AutoNumber5">
????? <tr>
??????? <td width="100%"><b><font face="黑体">全文辅助工具之一:上传文件接收</font></b></td>
????? </tr>
????? <tr>
??????? <td width="100%">
??????? <p align="right"><font color="#FF0000" size="2">作者:qixiaorui</font></td>
????? </tr>
??? </table>
??? </td>
??? <td width="5%"> </td>
? </tr>
? <tr>
??? <td width="15%"> </td>
??? <td width="80%">
??? <table border="1" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111"
??????? width="100%" id="AutoNumber2">
????? <tr>
??????? <td width="100%">
??????? <form method="POST" enctype="multipart/form-data" action="http://localhost:8080/UpAndDownTest/upload">
????????? <table border="0" cellpadding="10" cellspacing="10" style="border-collapse: collapse"
??????????????????????? bordercolor="#111111" width="100%" id="AutoNumber3">
??????????? <tr>
????????????? <td width="100%" bgcolor="#00FFFF">
????????????? <p align="center"><font face="华文仿宋" color="#000080"><b>
????????????? --------------------------------- 上 传 文 件
????????????? ----------------------------------</b></font></td>
??????????? </tr>
??????????? <tr>
????????????? <td width="100%">
????????????? <table border="0" cellpadding="3" cellspacing="3" style="border-collapse: collapse"
??????????????????????????? bordercolor="#111111" width="100%" id="AutoNumber4">
??????????????? <tr>
????????????????? <td width="27%">请输入服务器路径:</td>
????????????????? <td width="73%"><input type="text" name="FilePath" size="52">??
????????????????? 如: c:\aa</td>
??????????????? </tr>
??????????????? <tr>
????????????????? <td width="27%">请输入操作ID:</td>
????????????????? <td width="73%"><input type="text" name="FileID" size="52"></td>
??????????????? </tr>
??????????????? <tr>
????????????????? <td width="27%">请输入文件路径:</td>
????????????????? <td width="73%"><input type="file" name="FileData" size="41"></td>
??????????????? </tr>
????????????? </table>
????????????? </td>
??????????? </tr>
??????????? <tr>
????????????? <td width="100%">
????????????? <input type="submit" value="提交" name="uploadfile">??
????????????? <input type="reset" value="重置" name="B2"></td>
??????????? </tr>
????????? </table>
??????? </form>
??????? </td>
????? </tr>
??? </table>
??? </td>
??? <td width="5%"> </td>
? </tr>
? <tr>
??? <td width="15%"> </td>
??? <td width="80%"> </td>
??? <td width="5%"> </td>
? </tr>
</table>
</body>
</html>
3:配置端代码:web.xml
<?xml version="1.0" encoding="iso-8859-1"?>
?? <web-app id="IDOLSearch">
??? ??? <display-name>test</display-name>
??? ??? <description>This is Idol Sever Default Web Application.</description>
??? ??? <servlet>
<servlet-name>UploadServlet</servlet-name>
??? <servlet-class>com.test.action.ServletAction</servlet-class>
</servlet>
<servlet-mapping>
??? <servlet-name>UploadServlet</servlet-name>
??? <url-pattern>/upload/*</url-pattern>
</servlet-mapping>
??? ??? <welcome-file-list>
??? ??????? <welcome-file>index.html</welcome-file>
??? ??? </welcome-file-list>??? ? ??? ???
??? </web-app>
=============================================================
对于web应用的一些下载可以用一些现成的插件,例如common-fileupload组件
下载地址:http://jakarta.apache.org/commons /fileupload/import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.commons.fileupload.*;
public class Upload extends HttpServlet {
??? private String uploadPath = "C:\\upload\"; // 用于存放上传文件的目录
??? private String tempPath = "C:\\upload\\tmp\"; // 用于存放临时文件的目录
public void doPost(HttpServletRequest request, HttpServletResponse response)
??? throws IOException, ServletException
{
??? try {
??????? DiskFileUpload fu = new DiskFileUpload();
??????? // 设置最大文件尺寸,这里是4MB
??????? fu.setSizeMax(4194304);
??????? // 设置缓冲区大小,这里是4kb
??????? fu.setSizeThreshold(4096);
??????? // 设置临时目录:
??????? fu.setRepositoryPath(tempPath);
??????? // 得到所有的文件:
??????? List fileItems = fu.parseRequest(request);
??????? Iterator i = fileItems.iterator();
??????? // 依次处理每一个文件:
??????? while(i.hasNext()) {
??????????? FileItem fi = (FileItem)i.next();
??????????? // 获得文件名,这个文件名包括路径:
??????????? String fileName = fi.getName();
??????????? if(fileName!=null) {
??????????????? // 在这里可以记录用户和文件信息
??????????????? // ...
??????????????? // 写入文件a.txt,你也可以从fileName中提取文件名:
??????????????? fi.write(new File(uploadPath + "a.txt"));
??????????? }
??????? }
??????? // 跳转到上传成功提示页面
??? }
??? catch(Exception e) {
??????? // 可以跳转出错页面
??? }
}
}
//当servlet收到浏览器发出的Post请求后,在doPost()方法中实现文件上传。以下是示例代码:
如果要在配置文件中读取指定的上传文件夹,可以在init()方法中执行:
public void init() throws ServletException {
??? uploadPath = ....
??? tempPath = ....
??? // 文件夹不存在就自动创建:
??? if(!new File(uploadPath).isDirectory())
??????? new File(uploadPath).mkdirs();
??? if(!new File(tempPath).isDirectory())
??????? new File(tempPath).mkdirs();
}
配置servlet,用记事本打开tomcat\webapps\你的webapp\WEB-INF\web.xml,没有的话新建一个。典型配置如下:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
??? PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
??? "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
??? <servlet>
??????? <servlet-name>Upload</servlet-name>
??????? <servlet-class>Upload</servlet-class>
??? </servlet>
??? <servlet-mapping>
??????? <servlet-name>Upload</servlet-name>
??????? <url-pattern>/fileupload</url-pattern>
??? </servlet-mapping>
</web-app>
配置好servlet后,启动tomcat,写一个简单的html测试:
<form action="fileupload" method="post" enctype="multipart/form-data" name="form1">
? <input type="file" name="file">
? <input type="submit" name="Submit" value="upload">
</form>
注意action="fileupload"其中fileupload是配置servlet时指定的url-pattern。
================================================================
还有如:commons-fileupload-1.2.1.jar
try?{
DiskFileItemFactory?dfif=new?DiskFileItemFactory();
ServletFileUpload?upload=new?ServletFileUpload(dfif);
upload.setSizeMax(10*1024*1024);
List?list=upload.parseRequest(request);
for(int?i=0;i<list.size();i++){
FileItem?item=(FileItem)?list.get(i);
String?name=item.getName();
String?path=this.getServletContext().getRealPath("/upload");
item.write(new?File(path,name));
}
}?catch?(Exception?e)?{
//?TODO?Auto-generated?catch?block
e.printStackTrace();
}
?
?