程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> JavaWeb文件上傳與下載功效解析

JavaWeb文件上傳與下載功效解析

編輯:關於JAVA

JavaWeb文件上傳與下載功效解析。本站提示廣大學習愛好者:(JavaWeb文件上傳與下載功效解析)文章只能為提供參考,不一定能成為您想要的結果。以下是JavaWeb文件上傳與下載功效解析正文


在開辟進程中文件的上傳下載很經常使用。這裡簡略的總結一下:

1.文件上傳必需知足的前提:
a、 頁面表單的method必需是post 由於get傳送的數據太小了
b、 頁面表單的enctype必需是multipart/form-data類型的
c、 表單中供給上傳輸出域
代碼細節: 客戶端表單中:<form enctype="multipart/form-data"/>
(假如沒有這個屬性,則辦事端讀取的文件途徑會由於閱讀器的分歧而分歧)
辦事端ServletInputStream is=request.getInputStream();用流的方法獲得要求注釋內容,進一步的解析。

2.上傳文件的細節:
(1)為何設置表單類型為:multipart/form-data.是設置這個表單傳遞的不是key=value值。傳遞的是字節碼.
表單與要求的對應關系:

如上可以看出在設置表單類型為:multipart/form-data以後,在HTTP要求體中將你選擇的文件初始化為二進制,如上圖中的Cookie之下的一串的隨機字符串下的內容。
但留意,在標識文件(即一串隨機字符串)所朋分出來的文件字節碼中有兩行特別字符,即第一行內容文件頭和一行空行。以後的第三行才是二進制的文件內容。
所以在辦事端接收客戶端上傳的文件時,獲得HTTP要求參數中的文件二進制時,要去失落前三行。

3.本身手工解析上傳的txt文件:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 假如一個表單的類型是post且enctype為multipart/form-date
 * 則一切數據都是以二進制的方法向辦事器上傳遞。
 * 所以req.getParameter("xxx")永久為null。
 * 只可以經由過程req.getInputStream()來獲得數據,獲得注釋的數據
 * 
 * @author wangxi
 *
 */
public class UpServlet extends HttpServlet {
 public void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  req.setCharacterEncoding("UTF-8");
  String txt = req.getParameter("txt");//前往的是null
  System.err.println("txt is :"+txt);
  System.err.println("=========================================");
  InputStream in = req.getInputStream();
//  byte[] b= new byte[1024];
//  int len = 0;
//  while((len=in.read(b))!=-1){
//   String s = new String(b,0,len);
//   System.err.print(s);
//  }
  BufferedReader br = new BufferedReader(new InputStreamReader(in));
  String firstLine = br.readLine();//讀取第一行,且第一行是分隔符號,即隨機字符串
  String fileName = br.readLine();//第二行文件信息,從中截掏出文件名
  fileName = fileName.substring(fileName.lastIndexOf("\\")+1);// xxxx.txt"
  fileName = fileName.substring(0,fileName.length()-1);

  br.readLine();
  br.readLine();
  String data = null;
  //獲得以後項目標運轉途徑
  String projectPath = getServletContext().getRealPath("/up");
  PrintWriter out = new PrintWriter(projectPath+"/"+fileName);
  while((data=br.readLine())!=null){
   if(data.equals(firstLine+"--")){
    break;
   }
   out.println(data);
  }
  out.close();
 }
}

4.應用apache-fileupload處置文件上傳:
框架:是指將用戶常常處置的營業停止一個代碼封裝。讓用戶可以便利的挪用。
今朝文件上傳的(框架)組件:
Apache—-fileupload -
Orialiy – COS – 2008() -
Jsp-smart-upload – 200M。
用fileupload上傳文件:

須要導入第三方包:

    Apache-fileupload.jar – 文件上傳焦點包。
    Apache-commons-io.jar – 這個包是fileupload的依附包。同時又是一個對象包。

焦點類:

    DiskFileItemFactory – 設置磁盤空間,保留暫時文件。只是一個具類。
    ServletFileUpload  - 文件上傳的焦點類,此類吸收request,並解析reqeust。
    ServletfileUpload.parseRequest(requdest)  - List<FileItem>
    注:一個FileItem就是一個標識的開端:---------243243242342 到 ------------------245243523452—就是一個FileItem

第一步:導入包:

第二步:書寫一個servlet完成doPost辦法

/**
 * DiskFileItemFactory結構的兩個參數
 * 第一個參數:sizeThreadHold - 設置緩存(內存)保留若干字節數據,默許為10K
 * 假如一個文件沒有年夜於10K,則直接應用內存直接保留成文件便可以了。
 * 假如一個文件年夜於10K,就須要將文件先保留莅臨時目次中去。
 * 第二個參數 File 是指暫時目次地位
 *
 */
public class Up2Servlet extends HttpServlet {
 public void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  req.setCharacterEncoding("UTf-8");
  //獲得項目標途徑
  String path = getServletContext().getRealPath("/up");
  //第一步聲明diskfileitemfactory工場類,用於在指的磁盤上設置一個暫時目次
  DiskFileItemFactory disk = 
    new DiskFileItemFactory(1024*10,new File("/home/wang/"));
  //第二步:聲明ServletFileUpoload,吸收下面的暫時目次
  ServletFileUpload up = new ServletFileUpload(disk);
  //第三步:解析request
  try {
   List<FileItem> list = up.parseRequest(req);
   //假如就一個文件
   FileItem file = list.get(0);
   //獲得文件名,領路徑
   String fileName = file.getName();
   fileName = fileName.substring(fileName.lastIndexOf("\\")+1);
   //獲得文件的類型
   String fileType = file.getContentType();
   //獲得文件的字節碼
   InputStream in = file.getInputStream();
   //聲明輸入字撙節
   OutputStream out = new FileOutputStream(path+"/"+fileName);
   //文件copy
   byte[] b = new byte[1024];
   int len = 0;
   while((len=in.read(b))!=-1){
    out.write(b,0,len);
   }
   out.close();

   long size = file.getInputStream().available();

   //刪除上傳的暫時文件
   file.delete();
   //顯示數據
   resp.setContentType("text/html;charset=UTf-8");
   PrintWriter op = resp.getWriter();
   op.print("文件上傳勝利<br/>文件名:"+fileName);
   op.print("<br/>文件類型:"+fileType);
   op.print("<br/>文件年夜小(bytes)"+size);



  } catch (Exception e) {
   e.printStackTrace();
  }

 }

}

5.應用該框架上傳多個文件:

第一步:修正頁面的表單為多個input type=”file”

<form action="<c:url value='/Up3Servlet'/>" method="post" enctype="multipart/form-data">
  File1:<input type="file" name="txt"><br/>
  File2:<input type="file" name="txt"><br/>
  <input type="submit"/>
 </form>

第二步:遍歷list

public class Up3Servlet extends HttpServlet {
 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  request.setCharacterEncoding("UTF-8");
  String path = getServletContext().getRealPath("/up");
  //聲明disk
  DiskFileItemFactory disk = new DiskFileItemFactory();
  disk.setSizeThreshold(1024*1024);
  disk.setRepository(new File("d:/a"));
  //聲明解析requst的servlet
  ServletFileUpload up = new ServletFileUpload(disk);
  try{
   //解析requst
   List<FileItem> list = up.parseRequest(request);
   //聲明一個list<map>封裝上傳的文件的數據
   List<Map<String,String>> ups = new ArrayList<Map<String,String>>();
   for(FileItem file:list){
    Map<String,String> mm = new HashMap<String, String>();
    //獲得文件名
    String fileName = file.getName();
    fileName = fileName.substring(fileName.lastIndexOf("\\")+1);
    String fileType = file.getContentType();
    InputStream in = file.getInputStream();
    int size = in.available();
    //應用對象類
    FileUtils.copyInputStreamToFile(in,new File(path+"/"+fileName));
    mm.put("fileName",fileName);
    mm.put("fileType",fileType);
    mm.put("size",""+size);

    ups.add(mm);
    file.delete();
   }
   request.setAttribute("ups",ups);
   //轉發
   request.getRequestDispatcher("/jsps/show.jsp").forward(request, response);

  }catch(Exception e){
   e.printStackTrace();
  }
 }
}

如上就是上傳文件的經常使用做法。如今我們在來看看fileupload的其他查用API.

 

斷定一個fileItem能否是file(type=file)對象或是text(type=text|checkbox|radio)對象:
boolean isFormField() 假如是text|checkbox|radio|select這個值就是true.

6.處置帶解釋信息的圖片

public class UpDescServlet extends HttpServlet {
 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  request.setCharacterEncoding("UTF-8");//可以獲得中文的文件名
  String path = getServletContext().getRealPath("/up");
  DiskFileItemFactory disk = 
    new DiskFileItemFactory();
  disk.setRepository(new File("d:/a"));
  try{
   ServletFileUpload up = 
     new ServletFileUpload(disk);
   List<FileItem> list = up.parseRequest(request);
   for(FileItem file:list){
    //第一步:斷定能否是通俗的表單項
    if(file.isFormField()){
     String fileName = file.getFieldName();//<input type="text" name="desc">=desc
     String value = file.getString("UTF-8");//默許以ISO方法讀取數據
     System.err.println(fileName+"="+value);
    }else{//解釋是一個文件
     String fileName = file.getName();
     fileName = fileName.substring(fileName.lastIndexOf("\\")+1);
     file.write(new File(path+"/"+fileName));
     System.err.println("文件名是:"+fileName);
     System.err.println("文件年夜小是:"+file.getSize());
     file.delete();
    }
   }
  }catch(Exception e){
   e.printStackTrace();
  }
 }

}

7.文件上傳的機能晉升
在解析request獲得FileItem的聚集的時刻,應用:

FileItemIterator it= up.getItemIterator(request);

比應用

List<FileItem> list = up.parseRequest(request);

機能上要好的多。
示例代碼:

public class FastServlet extends HttpServlet {


 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  request.setCharacterEncoding("UTF-8");
  String path = getServletContext().getRealPath("/up");
  DiskFileItemFactory disk = 
    new DiskFileItemFactory();
  disk.setRepository(new File("d:/a"));
  try{
   ServletFileUpload up = new ServletFileUpload(disk);
   //以下是迭代器形式
   FileItemIterator it= up.getItemIterator(request);
   while(it.hasNext()){
    FileItemStream item = it.next();
    String fileName = item.getName();
    fileName=fileName.substring(fileName.lastIndexOf("\\")+1);
    InputStream in = item.openStream();
    FileUtils.copyInputStreamToFile(in,new File(path+"/"+fileName));
   }
  }catch(Exception e){
   e.printStackTrace();
  }

 }

}

8.文件的下載
既可所以get也能夠是post。

public void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  req.setCharacterEncoding("UTF-8");
  String name = req.getParameter("name");
  //第一步:設置呼應的類型
  resp.setContentType("application/force-download");
  //第二讀取文件
  String path = getServletContext().getRealPath("/up/"+name);
  InputStream in = new FileInputStream(path);
  //設置呼應頭
  //對文件名停止url編碼
  name = URLEncoder.encode(name, "UTF-8");
  resp.setHeader("Content-Disposition","attachment;filename="+name);
  resp.setContentLength(in.available());

  //第三步:開端文件copy
  OutputStream out = resp.getOutputStream();
  byte[] b = new byte[1024];
  int len = 0;
  while((len=in.read(b))!=-1){
   out.write(b,0,len);
  }
  out.close();
  in.close();
 }

在應用J2EE風行框架時

應用框架外部封裝好的來完成上傳下載更加簡略:

Struts2完成上傳.

在應用Struts2停止開辟時,導入的jar包不難發明存在 commons-fileupload-1.3.1.jar 包。經由過程下面的進修我們曾經可使用它停止文件的上傳下載了。但Struts2在停止了進一步的封裝。

view

<form action="fileUpload.action" method="post" enctype="multipart/form-data">
   
  username: <input type="text" name="username"><br>
  file: <input type="file" name="file"><br>

  <input type="submit" value="submit">
 </form>

Controller

public class FileUploadAction extends ActionSupport
{
 private String username;

   //留意,file其實不是指前端jsp上傳過去的文件自己,而是文件上傳過去寄存在暫時文件夾上面的文件
 private File file;

 //提交過去的file的名字
 //struts會主動截取前次文件的名字注入給該屬性
 private String fileFileName;
 //getter和setter此時為了勤儉篇幅免卻
  @Override
 public String execute() throws Exception
 {
 //保留上傳文件的途徑
  String root = ServletActionContext.getServletContext().getRealPath("/upload");
  //獲得暫時文件輸出流
  InputStream is = new FileInputStream(file);
  //輸入文件
  OutputStream os = new FileOutputStream(new File(root, fileFileName));
  //打印出上傳的文件的文件名
  System.out.println("fileFileName: " + fileFileName);
    // 由於file是寄存在暫時文件夾的文件,我們可以將其文件名和文件途徑打印出來,看和之前的fileFileName能否雷同
  System.out.println("file: " + file.getName());
  System.out.println("file: " + file.getPath());

  byte[] buffer = new byte[1024];
  int length = 0;

  while(-1 != (length = is.read(buffer, 0, buffer.length)))
  {
   os.write(buffer);
  }

  os.close();
  is.close();

  return SUCCESS;
 }
}

起首我們要清晰一點,這裡的file其實不是真正指代jsp上傳過去的文件,當文件上傳過去時,struts2起首會尋覓struts.multipart.saveDir(這個是在default.properties外面有)這個name所指定的寄存地位(默許是空),我們可以在我們項目標struts2中來指定這個暫時文件寄存地位。

 <constant name="struts.multipart.saveDir" value="/repository"/> 

 假如沒有設置struts.multipart.saveDir,那末將默許應用javax.servlet.context.tempdir指定的地址,javax.servlet.context.tempdir的值是由辦事器來肯定的,例如:假設我的web工程的context是abc,辦事器應用Tomcat,那末savePath就應當是%TOMCAT_HOME%/work/Catalina/localhost/abc_,暫時文件的稱號相似於upload__1a156008_1373a8615dd__8000_00000001.tmp,每次上傳的暫時文件名能夠分歧,然則年夜致是這類款式。並且假如是應用Eclipse中的Servers外面設置裝備擺設Tomcat並啟動的話,那末下面地址中的%TOMCAT_HOME%將不會是體系中的現實Tomcat根目次,而會是Eclipse給它指定的地址,例如我當地的地址是如許的:/home/wang/EclipseJavaCode/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/work/Catalina/localhost/abc/upload__1a156008_1373a8615dd__8000_00000001.tmp。

Struts2完成下載.

struts2的文件下載更簡略,就是界說一個輸出流,然後將文件寫到輸出流外面就行,症結設置裝備擺設照樣在struts.xml這個設置裝備擺設文件裡設置裝備擺設:

public class FileDownloadAction extends ActionSupport
{
 //要下載文件在辦事器上的途徑
 private String path;
 //要下載文件的文件名
 private String downloadFileName;
 //寫入getter和setter
 public InputStream getDownloadFile()
 {
  return ServletActionContext.getServletContext().getResourceAsStream(path);
 }

 @Override
 public String execute() throws Exception
 {
 //以後action默許在valuestack的棧頂
  setDownloadFileName(xxx);
  return SUCCESS;
 }
}

action只是界說了一個輸出流downloadFile,然後為其供給getter辦法就行,接上去我們看看struts.xml的設置裝備擺設文件:

 <action name="fileDownload" class="com.struts2.FileDownloadAction">
    <result name="download" type="stream">
  <param name="contentDisposition">attachment;fileName="${downloadFileName}"</param>
  <param name="inputName">downloadFile</param>
   </result>
 </action>

struts.xml設置裝備擺設文件有幾個處所我們要留意,起首是result的類型,type必定要界說成stream類型_,告知action這是文件下載的result,result元素外面普通還有param子元素,這個是用來設定文件下載時的參數,inputName這個屬性就是獲得action中的文件輸出流,名字必定要和action中的輸出流屬性名字雷同,然後就是contentDisposition屬性,這個屬性普通用來指定我們願望經由過程怎樣樣的方法來處置下載的文件,假如值是attachment,則會彈出一個下載框,讓用戶選擇能否下載,假如不設定這個值,那末閱讀器會起首檢查本身可否翻開下載的文件,假如能,就會直接翻開所下載的文件,(這固然不是我們所須要的),別的一個值就是filename這個就是文件鄙人載時所提醒的文件下載名字。在設置裝備擺設完這些信息後,我們就可以過完成文件的下載功效了。

SpringMVC完成上傳:

view於struts2示例中的完整一樣。此出不在寫出。

Controller:

@Controller
@RequestMapping(value="fileOperate")
public class FileOperateAction {
 @RequestMapping(value="upload")
 public String upload(HttpServletRequest request,@RequestParam("file") MultipartFile photoFile){
 //上傳文件保留的途徑
  String dir = request.getSession().getServletContext().getRealPath("/")+"upload";
  //原始的文件名
  String fileName = photoFile.getOriginalFilename();      //獲得文件擴大名
  String extName = fileName.substring(fileName.lastIndexOf(".")); 
 //避免文件名抵觸,把名字小小修正一下
 fileName = fileName.substring(0,fileName.lastIndexOf(".")) + System.nanoTime() + extName; 
  FileUtils.writeByteArrayToFile(new File(dir,fileName),photoFile.getBytes());
  return "success";
 }
 }

SpringMVC完成下載:

 @RequestMapping("/download")
 public String download(String fileName, HttpServletRequest request,
   HttpServletResponse response) {
  response.setCharacterEncoding("utf-8");
  response.setContentType("multipart/form-data");
  response.setHeader("Content-Disposition", "attachment;fileName="
    + fileName);
  try {
   InputStream inputStream = new FileInputStream(new File(文件的途徑);

   OutputStream os = response.getOutputStream();
   byte[] b = new byte[2048];
   int length;
   while ((length = inputStream.read(b)) > 0) {
    os.write(b, 0, length);
   }

    // 這裡重要封閉。
   os.close();

   inputStream.close();
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
   // 前往值要留意,要否則就湧現上面這句毛病!
   //java+getOutputStream() has already been called for this response
  return null;
 }

以上就是本文的全體內容,願望對年夜家的進修有所贊助,也願望年夜家多多支撐。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved