1. 程式人生 > >檔案上傳---檔案解壓---讀取檔案---檔案重新命名壓縮

檔案上傳---檔案解壓---讀取檔案---檔案重新命名壓縮

JAVA開發web專案 程式碼的順序是按照程式碼執行的順序寫的,以下寫的是沒有傳遞id情況下,即是新增檔案情況

jsp頁面用uploadify外掛實現檔案上傳

//觸發上傳外掛的html頁面程式碼
<span class="chooseNodeSmall" onclick="fileUpload('')" style="margin-left:10px">檔案上傳</span>

	<!-- 上傳開始  上傳彈出框 -->
	<div  id="fileUpload" style=" display: none; position: absolute; left: 20%; top: 30%;width:450px;height:170px;overflow:hidden;border:3px solid #98999D;padding:12px;border-radius:10px;z-index:10;background-color:white">
		<br>
		<div style="height:130px">
			 <input id="uploadify" type="file" name="uploadify"/>
			 <input type="hidden" name="id" id="updateDocId"/>
			 <span onclick="closeFileUploadWindow()" style="position:absolute;left:420px;top:10px" class="uploadType">關閉</span>
		</div>
		<div style="height:30px" >
          	 <a href="javascript:$('#uploadify').uploadify('upload','*')"  class="uploadType">開始上傳</a>    
   			<a href="javascript:$('#uploadify').uploadify('cancel')" class="uploadType">取消上傳</a>    
		</div>
	</div>
	<div id="mask" style="display:none"></div>//用於顯示彈出框下層的陰影

css程式碼
<style type="text/css">
.chooseNodeSmall{
	cursor:pointer;
	background-color:#7F99BE;
	border:1px solid #D3D3D3;
	padding:4px 7px;
	color:white;
	font-weight:bold;
	font-size:13px;
	margin-left:30px;
}
#mask{
	width: 100%;
	height: 200%;
	position: absolute;
	background-color: #000;
	left: 0;
	opacity:0.5;
	top: 0;
	z-index: 8;
}
</style>
js程式碼
function fileUpload(id){
	$("#mask").show();
	$("#fileUpload").css("display","block");
	$("#updateDocId").val(id);
}
function closeFileUploadWindow(){
	$("#mask").hide();
	$("#fileUpload").css("display","none");
}
uploadify外掛js程式碼實現
$(function(){
		 $("#uploadify").uploadify({  
			 'swf' : "${pageContext.request.contextPath}/static/js/uploadify/uploadify.swf",
			  'uploader'  : "${pageContext.request.contextPath}/document/uploadFile",//檔案上傳地址
			  'queueId' : "fileQueue",
			  'queueSizeLimit' : 1,//限制上傳檔案的數量
			  'fileExt' : "*.rar,*.zip",//'fileDesc' : "RAR *.rar",//限制檔案型別
			  'fileTypeDesc'   : '壓縮檔案',    //可選擇檔案型別說明  
			  'auto'  : false, //是否直接上傳,若為true則不用點選開始上傳
			  'multi'  : true,//是否允許多檔案上傳
			  'method'   :'post',
			  'width'     : '65',  //按鈕寬度    
	                  'height'    : '18',  //按鈕高度  
			  'simUploadLimit': 2,//同時執行上傳的程序數量
			  'scriptData': { "id": $("#updateDocId").val()},//傳遞其它的引數-----#***************
			  'buttonText': "選擇檔案",
			  'fileObjName' : 'uploadFile',
			  'onFallback':function(){      
	                alert("您未安裝FLASH控制元件,無法上傳圖片!請安裝FLASH控制元件後再試。");      
	            },  
	            'onUploadStart' : function(file) {
	            	$("#uploadify").uploadify("settings", "formData", {'id' : $("#updateDocId").val()});  <span style="font-family: Arial, Helvetica, sans-serif;">//傳遞其它的引數(檔案ID值,若有則為更新檔案)----#***************</span>
 
	            },
	            'onUploadSuccess' : function(file, data, response){//單個檔案上傳成功觸發    
	            	var json = eval('(' + data + ')'); //解析成JSON格式
	            	if(json.flag){
	            		flag += 1;
	            		$.messager.alert("info",json.msg,"success");
	            		$('#uploadify').uploadify('cancel');
	            		closeFileUploadWindow();
	            	}else{
	            		$.messager.alert("info",json.msg,"error");
	            	}
	            }, 
		    });  
	})

本專案用的是spring+springmvc+jpa開發框架

controller層程式碼

/**
	 * 新增檔案或更新檔案,根據有沒有傳檔案ID值來區分
	 * @return
	 */
	@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
	public ResponseEntity<?> uploadFile(@RequestParam("uploadFile") CommonsMultipartFile file,HttpServletResponse response,HttpServletRequest request) {
		//文件更新與新增的公共程式碼
		Map<String, String> map = new HashMap<String, String>();
		String fileName = file.getOriginalFilename();
		String[] split = fileName.split("\\.");
		if(split.length >2){
			map.put("msg", "壓縮檔案命名不規範,只能存在一個點");
			return new ResponseEntity<Map<String, String>>(map, HttpStatus.OK);
		}
		File newFile = new File(PropsUtil.getProperty("document.FirstPath")+File.separatorChar+fileName);
		if(!new File(PropsUtil.getProperty("document.FirstPath")).exists()){
			new File(PropsUtil.getProperty("document.FirstPath")).mkdirs();
		}
		if(StringUtils.equals(split[1],"zip")){
			if(split[0].length() < 50 && StringUtils.isNotBlank(split[0])){
				String param_id = request.getParameter("id");
				if(StringUtils.isNotBlank(param_id)){
					//此時為更新
					//首先將該ID的檔案全部刪除
					FileUtil.delete(new File(PropsUtil.getProperty("document.actualPath") + param_id +".zip"));
					FileUtil.deltree(new File(PropsUtil.getProperty("document.actualIconPath") + param_id ));
					try {
						file.transferTo(newFile);
						Map<String, String>  analyzeResult = analyzeFile(PropsUtil.getProperty("document.FirstPath")+File.separatorChar + fileName,param_id,split[0]);
						System.out.println("analyzeResult-------------------------------"+analyzeResult.toString());
						
						Document document = new Document();
						document.setId(param_id);
						//查詢該記錄的版本號,在些基礎上加1
						int oldVersion = documentService.getOldVersionById(param_id);
						document.setDocument_version(++oldVersion);
						if(!analyzeResult.containsKey("msg")){
							map = saveDocInfo(map, split, document, analyzeResult);
							System.out.println("map-------------------------------"+map.toString());
							if(map.containsKey("flag")){
								map.put("msg", "檔案更新成功");
							}
						}else{
							map.put("msg", analyzeResult.get("msg"));
						}
						return new ResponseEntity<Map<String, String>>(map, HttpStatus.OK);
					} catch (IllegalStateException | IOException e) {
						logger.error("資料uploadFile異常:", e);
						//刪除原檔案
						FileUtil.delete(new File(PropsUtil.getProperty("document.FirstPath")+File.separatorChar+fileName));
						throw new RestException(messageSourceHelper.getMessage(e.getMessage()));
					}
					
				}else{
					//此時為新增新檔案
					try {
						//儲存檔案資訊,使最後的修改的檔名為記錄的id,這步很重要
						Document doc = documentService.saveDoc(split[0]);
						file.transferTo(newFile);
						Map<String, String>  analyzeResult = analyzeFile(PropsUtil.getProperty("document.FirstPath")+File.separatorChar + fileName,doc.getId(),split[0]);
						System.out.println("analyzeResult-------------------------------"+analyzeResult.toString());
						if(!analyzeResult.containsKey("msg")){
								map = saveDocInfo(map, split, doc, analyzeResult);
								System.out.println("map-------------------------------"+map.toString());
						}else{
							map.put("msg", analyzeResult.get("msg"));
						}
						return new ResponseEntity<Map<String, String>>(map, HttpStatus.OK);
					} catch (Exception e) {
						logger.error("資料uploadFile異常:", e);
						//刪除原檔案
						FileUtil.delete(new File(PropsUtil.getProperty("document.FirstPath")+File.separatorChar+fileName));
						throw new RestException(messageSourceHelper.getMessage(e.getMessage()));
					}
				}
			}else{
				map.put("msg", "上傳壓縮檔名不能超過50個字元");
			}
		}else{
			map.put("msg", "請選擇zip檔案上傳");
		}
		
		return null;
	}
匯入ant.jar包,import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipFile;用util.zip的包會報錯,
/**
 * 
 * @param filePath 需要解析的檔案路徑(zip檔案)
 * @param id 檔案的新名稱,若不想改名,可傳原檔名
 * @param fileName2 解析的檔名
 * @return
 */
	private Map<String, String>  analyzeFile(String filePath, String id, String fileName2) {
		Map<String, String> map = new HashMap<String, String>();
		//將檔案解壓縮----------start
		ZipFile zipFile;
		try {
			zipFile = new ZipFile(filePath);
			Enumeration<ZipEntry> enu = (Enumeration<ZipEntry>) zipFile.getEntries();
			while (enu.hasMoreElements()) {
				ZipEntry zipElement = (ZipEntry) enu.nextElement();// 單個檔案 物件
				InputStream read = zipFile.getInputStream(zipElement); // 單個檔案檔案的流
				String fileName = zipElement.getName(); // 單個檔名字
				
				String outPath = (PropsUtil.getProperty("document.unzipPath")+ File.separator + fileName).replaceAll("\\*", "/");
				// 判斷路徑是否存在,不存在則建立檔案路徑
				File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
				if (!file.exists()) {
					file.mkdirs();
				}
				// 判斷檔案全路徑是否為資料夾,如果是,不需要解壓
				if (new File(outPath).isDirectory()) {
					continue;
				}
				OutputStream out = new FileOutputStream(outPath);
				byte[] buf1 = new byte[1024];
				int len;
				//將zipFileT中的檔案複製到uploadFile資料夾中
				while ((len = read.read(buf1)) > 0) {
					out.write(buf1, 0, len);
				}
				read.close();
				out.close();
			}
			zipFile.close();
			//將檔案解壓縮----------end
			
			//刪除原檔案
			FileUtil.delete(filePath);
			//讀取config.json到MAP中(config.json是上傳檔案的配置檔案,業務需求,要讀取裡面的內容儲存到資料庫)
			map = readConfigMsgToMap(fileName2);
			 //檔案標題不能重複,若重複提示報錯
		    Boolean flag =  documentService.findRepeatTitle(map.get("title"));
		    if(flag){
		    	//此時說明資料庫中已經存在相同的標題,
		    	//刪除解壓資料夾
		    	FileUtil.deltree(new File(PropsUtil.getProperty("document.unzipPath")+ File.separator + fileName2));
		    	//刪除該條記錄
		    	documentService.delete(id);
		    	map.put("msg", "上傳檔案標題已存在,請修改壓縮檔案裡config.json檔案的title值");
		    	return map;
		    }
		    
			//更改檔名,為後面壓縮檔案做準備
			File f1 = new File(PropsUtil.getProperty("document.unzipPath")+ File.separator + fileName2);
			File f2 = new File(PropsUtil.getProperty("document.unzipPath")+ File.separator + id);
			boolean renameTo = f1.renameTo(f2);//這一步有時會報錯,那是因為流沒有關閉,一定要確保上面用到的流全部關閉
			System.out.println("f1---"+f1+"renameTo ---f2"+f2+"---"+renameTo);
			boolean fileToZip = fileToZip(PropsUtil.getProperty("document.unzipPath"), PropsUtil.getProperty("document.actualPath"), id);//將解壓後的檔案重新壓縮,重新命名********************
			//將檔案的icon.png檔案複製到目標資料夾
			FileUtil.copyFile(PropsUtil.getProperty("document.unzipPath")+ id+ File.separator + map.get("icon"), PropsUtil.getProperty("document.actualIconPath")+ id+ File.separator + "icon.png", true);//這步還沒有刪除之前解壓的檔案,取出圖片放到目標位置,備用
			//如果壓縮檔案成功,將被壓縮的檔案刪除
			if(fileToZip){
				FileUtil.deltree(new File(PropsUtil.getProperty("document.unzipPath")+ File.separator + id));
			}else{
				//刪除解壓資料夾
		    	FileUtil.deltree(new File(PropsUtil.getProperty("document.unzipPath")+ File.separator + fileName2));
				map.put("msg", "檔案壓縮失敗");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return map;
	}
下面是資料夾的壓縮,花費了很長時間才解決,有部分程式碼是轉別人的,但他的只能壓縮單個檔案,不能壓縮資料夾,在他的基礎上做了修改,實現了壓縮資料夾
  /** 
     * 將存放在sourceFilePath目錄下的原始檔,打包成fileName名稱的zip檔案,並存放到zipFilePath路徑下 
     * @param sourceFilePath :待壓縮的檔案路徑 
     * @param zipFilePath :壓縮後存放路徑 
     * @param fileName :壓縮後文件的名稱 
     * @return 
     */  
    public static boolean fileToZip(String sourceFilePath,String zipFilePath,String fileName){  
        boolean flag = false;  
        File sourceFile = new File(sourceFilePath);  
        FileInputStream fis = null;  
        BufferedInputStream bis = null;  
        FileOutputStream fos = null;  
        ZipOutputStream zos = null;  
          
        if(sourceFile.exists() == false){  
            System.out.println("待壓縮的檔案目錄:"+sourceFilePath+"不存在.");  
        }else{  
            try {  
                File zipFile = new File(zipFilePath + "/" + fileName +".zip");  
                if(zipFile.exists()){  
                    System.out.println(zipFilePath + "目錄下存在名字為:" + fileName +".zip" +"打包檔案.");  
                }else{
                	File file = new File(zipFilePath);
    				if (!file.exists()) {
    					file.mkdirs();
    				}
                    File[] sourceFiles = sourceFile.listFiles();  
                    if(null == sourceFiles || sourceFiles.length<1){  
                        System.out.println("待壓縮的檔案目錄:" + sourceFilePath + "裡面不存在檔案,無需壓縮.");  
                    }else{  
                        fos = new FileOutputStream(zipFile);  
                        zos = new ZipOutputStream(new BufferedOutputStream(fos));  
                        byte[] bufs = new byte[1024*10];  
                        for(int i=0;i<sourceFiles.length;i++){  
                            //建立ZIP實體,並新增進壓縮包  
                            ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());  
                            //讀取待壓縮的檔案並寫進壓縮包裡  
                            if(sourceFiles[i].isDirectory()){
                            	//遞迴讀取檔案流中資料
                            	 parseFileToZip(sourceFiles[i],"", zos);//實現壓縮資料夾關鍵****************
                            }else{
                            	zos.putNextEntry(zipEntry);
                            	fis = new FileInputStream(sourceFiles[i]);  
                            	bis = new BufferedInputStream(fis, 1024*10);  
                            	int read = 0;  
                            	while((read=bis.read(bufs, 0, 1024*10)) != -1){  
                            		zos.write(bufs,0,read);  
                            	}  
                            }
                        }  
                    }  
                }  
                flag = true;  
            } catch (FileNotFoundException e) {  
                e.printStackTrace();  
                throw new RuntimeException(e);  
            } catch (IOException e) {  
                e.printStackTrace();  
                throw new RuntimeException(e);  
            } finally{  
                //關閉流  
                try {  
                    if(null != bis) bis.close();  
                    if(null != zos) zos.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                    throw new RuntimeException(e);  
                }  
            }  
        }  
        return flag;  
    }
實現壓縮資料夾關鍵
 /**
     * @param file  輸入檔案
     * @param oppositePath 檔案層級(必有,否則壓縮後的檔案沒有層級結構)
     * @param zos2 輸出流
     */
    
	private static void parseFileToZip(File file,String oppositePath, ZipOutputStream zos2) {
		oppositePath = oppositePath +file.getName()+"/";
		ZipEntry zipEntry = new ZipEntry(oppositePath); 
		try {
			zos2.putNextEntry(zipEntry);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	    FileInputStream fis = null;  
	    BufferedInputStream bis = null;  
		File[] sf = file.listFiles();
		for(int i=0;i<sf.length;i++){ 
			if(sf[i].isDirectory()){
            	 parseFileToZip(sf[i],oppositePath, zos2);
            }else{
            	try {
            		ZipEntry zipEntryC = new ZipEntry(oppositePath + sf[i].getName());
            		zos2.putNextEntry(zipEntryC);
					byte[] bufs = new byte[1024*10];  
					fis = new FileInputStream(sf[i]);  
					bis = new BufferedInputStream(fis, 1024*10);  
					int read = 0;  
					while((read=bis.read(bufs, 0, 1024*10)) != -1){  
						zos2.write(bufs,0,read);  
					}
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				} finally{  
	                //關閉流  
	                try {  
	                    if(null != fis) fis.close();  
	                    if(null != bis) bis.close();  
	                } catch (IOException e) {  
	                    e.printStackTrace();  
	                    throw new RuntimeException(e);  
	                }  
	            }    
            }
		}
	}

ps:outputstream(輸出流必須到資料夾下重新命名的檔案,輸出目標檔案的所在的資料夾必須存在,沒有則要先建立,否則會報找一到檔案錯誤),inputstream(輸入流必須到檔案,否則會報錯)**************************

因為更新與新增都用到saveDocInfo,所以提出來了,這一步是將config.json讀出的資料儲存到資料庫中,當然是更新記錄,因為id已經存在了

/**
	 * @param map
	 * @param split
	 * @param doc
	 * @param analyzeResult
	 */
	private Map<String, String> saveDocInfo(Map<String, String> map, String[] split, Document doc, Map<String, String> analyzeResult) {
		if(StringUtils.isNotBlank(analyzeResult.get("icon")) && StringUtils.isNotBlank(analyzeResult.get("path")) && StringUtils.isNotBlank(analyzeResult.get("title"))){
			//檔案資訊儲存到資料庫
			doc.setId(doc.getId());
			doc.setDocument_icon(doc.getId() + File.separator +"icon.png");
			doc.setDocument_page_count(Integer.parseInt(analyzeResult.get("pages")));
			doc.setDocument_md5_sum(getMD5(new File(PropsUtil.getProperty("document.actualPath")+File.separatorChar + doc.getId()+".zip")));
			doc.setDocument_name(split[0]);
			doc.setDocument_summary(analyzeResult.get("describe"));
			doc.setDocument_title(analyzeResult.get("title"));
			doc.setUpdate_time(new Date());
			doc.setDocument_is_new(0);
			doc.setDocument_download_path("zipfiles/"+doc.getId()+".zip");
			doc.setDocument_local_path(PropsUtil.getProperty("document.actualPath")+doc.getId()+".zip");
			if(doc.getDocument_version()!=null){
				doc.setDocument_version(doc.getDocument_version() +1);
			}else{
				doc.setDocument_version(1);
			}
			if(StringUtils.isNotBlank(analyzeResult.get("tags"))){
				doc.setDocument_keywords(analyzeResult.get("tags"));
			}
			if(StringUtils.isNotBlank(analyzeResult.get("type"))){
				doc.setDocument_type(analyzeResult.get("type"));
			}
			//獲取檔案大小
			File filed = new File(PropsUtil.getProperty("document.actualPath")+ doc.getId()+".zip" );
			if(filed.exists()){
				doc.setDocument_size((int)filed.length());
			}
			documentService.saveEntity(doc);
			if(!map.containsKey("msg")){
				map.put("msg",  "檔案上傳成功");
				map.put("flag",  "true");
			}
		}else{
			map.put("msg",  "請檢查上傳檔案完整性");
		}
		return map;
	}
到此結束,程式碼主要都在controller層,其它層就不寫了