最近的項目中涉及到文件的上傳跟下載的問題,就自己所涉及到的方面做出如下表述。
首先是文件上傳部分,項目的要求是通用性較好,所以只需要傳入目標路徑即可。參數的傳遞通過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 }