java上傳文件跟批量下載文件


  最近的項目中涉及到文件的上傳跟下載的問題,就自己所涉及到的方面做出如下表述。

  首先是文件上傳部分,項目的要求是通用性較好,所以只需要傳入目標路徑即可。參數的傳遞通過Form表單傳值,在目標路徑下新建一個File類型的文件,然后通過流的方式將需要上傳的文件寫入新建的文件中。此方法適用於web開發過程中上傳文檔類的文件,如果你文件過大請研究ftp相關的知識,筆者所接觸的ftp傳文件限於C#中,這里不做表述。具體代碼如下:

 1 public void fileUpload(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
 2     {
 3         String filePath = new String();
 4         request.setCharacterEncoding("UTF-8");
 5         response.setContentType("text/html; charset=GB2312");
 6         try
 7         {
 8             DiskFileItemFactory factory = new DiskFileItemFactory();
 9             //設置緩存中最大允許緩存為2M
10             factory.setSizeThreshold(2 * 1024 * 1024);
11             ServletFileUpload upload = new ServletFileUpload(factory);
12             //解決中文文件名為亂碼的問題
13             upload.setHeaderEncoding("UTF-8");
14             List<FileItem> fileList = upload.parseRequest(request);
15             Iterator iter = fileList.iterator();
16             String newFileName = "";
17             while (iter.hasNext())
18             {
19                 //獲取文件
20                 FileItem fileItem = (FileItem)iter.next();
21                 //獲取文件上傳的路徑
22                 String typeName = fileItem.getFieldName();
23                 if(("destPath").equals(typeName))
24                 {
25                     filePath = fileItem.getString("utf-8");
26                 }
27                 if(("filename").equals(typeName))
28                 {
29                     newFileName = fileItem.getString("utf-8");
30                 }
31                 String fileName = new String();
32                 if (!fileItem.isFormField()) 
33                 {
34                     String name = fileItem.getName();
35                     if(StringUtil.isNullOrEmpty(name))
36                     {    
37                         continue;
38                     }
39                     fileName = name;
40                     fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
41                     File file = new File(filePath);
42                     if(!file.exists())
43                     {
44                         file.mkdirs();
45                     }
46                     //向指定的路徑寫文件
47                     if(newFileName.length()>0)
48                     {
49                         fileName = newFileName;
50                     }
51                     fileItem.write(new File(filePath, fileName));
52                 }
53             }
54         }
55         catch (Exception ex) 
56         {
57             throw new ServletException("上傳文件失敗!", ex);
58         }
59     }

  第二部分是關於文件批量下載的文檔。根據客戶的觀點有上傳就要下載的需求,一開始也做了相關的開發,結果發現下載時的文件全部存在服務器端,跟需求不一致。仔細推敲了下代碼原來自己寫的有問題,在客戶端是選擇文件的存儲路徑,然后將文件下載,其實只是實現了本地的遷移,並沒有在把文件下載到客戶端。后來的想法是把文件打包下載,用FileOutputStream,實現下載的問題,可是如果下載的文件中含有中文字符,就會出現亂碼。不得已百度了下,原來是編碼的問題,使用java自帶的文件輸出類不能解決壓縮文件中文件名亂碼的問題。解決方法:使用ant.jar包,創建壓縮文件時,可以設置文件的編碼格式,文件名亂碼的問題就解決了。由於筆者在開發過程中數據庫中有文件的路徑,所以下列文件的文件路徑的獲取是查詢得到。

  具體的解決代碼如下:

  引用ant.jar包中的FileOutputStream類

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

  打包下載多個文件的思路就是在服務端創建一個新的壓縮文件(zip格式),然后將下載的多個文件寫入該壓縮包中,然后以流的形式輸出壓縮文件寫到客戶端,實現下載功能。

  1   public void downloadFiles(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
  2    {
  3        request.setCharacterEncoding("UTF-8");
  4        String docId = new String(request.getParameter("docId").getBytes("ISO-8859-1"), "UTF-8");
  5        String downloadType = new String(request.getParameter("downloadType").getBytes("ISO-8859-1"), "UTF-8");
  6         
  7        Document doc = null;
  8        try
  9        {
 10           doc = getFilePath(docId);  //此方法獲取文件的路徑,這個不顯示
 11       }
 12       catch (SQLException ex)
 13       {
 14          ex.printStackTrace();
 15       }
 16    
 17       List<Element> elements = doc.getRootElement().elements();
 18       List<File> files = new ArrayList<File>();
 19       int index = 0;
 20       long fileLength = 0;
 21       for(Element ele : elements)
 22       {
 23          String filePath = FormatUtil.tryGetItemText(ele, "FILE_PATH", "") + FormatUtil.tryGetItemText(ele, "FILE_NAME", "");
 24          File file = new File(filePath);
 25          files.add(file);
 26          fileLength += file.length();
 27          index++;
 28       }
 29       String fileName = UUID.randomUUID().toString() + ".zip";
 30       //在服務器端創建打包下載的臨時文件
 31       String outFilePath = "C:\\" + fileName;
 32       File file = new File(outFilePath);
 33       //文件輸出流
 34       FileOutputStream outStream = new FileOutputStream(file);
 35       //壓縮流
 36       ZipOutputStream toClient = new ZipOutputStream(outStream);
 37       toClient.setEncoding("gbk");
 38       zipFile(files, toClient);
 39       toClient.close();
 40       outStream.close();
 41       this.downloadZip(file, response);
 42  }
 43   /**
 44    * 壓縮文件列表中的文件
 45    * @param files
 46    * @param outputStream
 47    * @throws IOException
 48    */
 49   public static void zipFile(List files, ZipOutputStream outputStream) throws IOException,ServletException
 50   {
 51       try
 52       {
 53          int size = files.size();
 54          //壓縮列表中的文件
 55          for(int i = 0; i < size; i++)
 56          {
 57              File file = (File) files.get(i);
 58              zipFile(file, outputStream);
 59           }
 60        }
 61        catch(IOException e)
 62        {
 63             throw e;
 64        }
 65 }
 66   /**
 67    * 將文件寫入到zip文件中
 68    * @param inputFile
 69    * @param outputstream
 70    * @throws Exception
 71    */
 72    public static void zipFile(File inputFile, ZipOutputStream outputstream) throws IOException,ServletException
 73    {
 74        try{
 75            if(inputFile.exists())
 76            {
 77               if(inputFile.isFile())
 78               {
 79                  FileInputStream inStream = new FileInputStream(inputFile);
 80                  BufferedInputStream bInStream = new BufferedInputStream(inStream);
 81                  ZipEntry entry = new ZipEntry(inputFile.getName());
 82                  outputstream.putNextEntry(entry);
 83                   
 84                  final int MAX_BYTE = 10 * 1024 *1024;    //最大的流為10M
 85                  long streamTotal = 0;                      //接受流的容量
 86                  int streamNum = 0;                      //流需要分開的數量
 87                  int leaveByte = 0;                      //文件剩下的字符數
 88                  byte[] inOutbyte;                          //byte數組接受文件的數據
 89                  
 90                  streamTotal = bInStream.available();                        //通過available方法取得流的最大字符數
 91                  streamNum = (int)Math.floor(streamTotal / MAX_BYTE);    //取得流文件需要分開的數量
 92                  leaveByte = (int)streamTotal % MAX_BYTE;                //分開文件之后,剩余的數量
 93                  
 94                  if (streamNum > 0) 
 95                  {
 96                      for(int j = 0; j < streamNum; ++j)
 97                      {
 98                          inOutbyte = new byte[MAX_BYTE];
 99                          //讀入流,保存在byte數組
100                          bInStream.read(inOutbyte, 0, MAX_BYTE);
101                          outputstream.write(inOutbyte, 0, MAX_BYTE);  //寫出流
102                       }
103                  }
104                  //寫出剩下的流數據
105                  inOutbyte = new byte[leaveByte];
106                  bInStream.read(inOutbyte, 0, leaveByte);
107                  outputstream.write(inOutbyte);
108                  outputstream.closeEntry();     //Closes the current ZIP entry and positions the stream for writing the next entry
109                  bInStream.close();    //關閉
110                  inStream.close();
111             }
112          }
113          else
114          {
115              throw new ServletException("文件不存在!");
116          }
117      }
118      catch(IOException e)
119      {
120          throw e;
121      }
122 }
123   /**
124    * 下載打包的文件
125    * @param file
126    * @param response
127    */
128   public void downloadZip(File file,HttpServletResponse response) {
129       try {
130           // 以流的形式下載文件。
131           BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file.getPath()));
132           byte[] buffer = new byte[fis.available()];
133           fis.read(buffer);
134           fis.close();
135           // 清空response
136           response.reset();
137   
138           OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
139           response.setContentType("application/octet-stream");
140           response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
141           toClient.write(buffer);
142           toClient.flush();
143           toClient.close();
144           file.delete();        //將生成的服務器端文件刪除
145        } 
146        catch (IOException ex) {
147           ex.printStackTrace();
148       }
149   }

  單個文件的下載直接下載文件即可,使用java自帶的FileOutputStream就能實現,可以從上面的批量下載中提取單個文件下載的方法。

  涉及到文件名稱編碼的問題,這里提供一個格式化中文字符串的方法。

  

 1 public static String toUtf8String(String s){ 
 2         StringBuffer sb = new StringBuffer(); 
 3         for (int i = 0;i < s.length(); i++){ 
 4             char c = s.charAt(i); 
 5             if (c >= 0 && c <= 255)
 6             {
 7                 sb.append(c);
 8             } 
 9             else{ 
10                 byte[] b; 
11                 try 
12                 { 
13                     b = Character.toString(c).getBytes("utf-8");
14                 } 
15                 catch (Exception ex) {
16                     b = new byte[0]; 
17                 } 
18                 for (int j = 0; j < b.length; j++) { 
19                     int k = b[j]; 
20                     if (k < 0) k += 256; 
21                     sb.append("%" + Integer.toHexString(k).toUpperCase()); 
22                 } 
23             } 
24         } 
25         return sb.toString(); 
26     }

 

  第一次寫,歡迎各位大牛指點。如有不正之處歡迎指出。希望對有需要的園友有幫助,筆者將不甚歡喜!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM