批量處理1——文件的上傳(bootstrap+Ajax+SSM)
批量處理2——Java花式處理EXCEL
批量處理3——Excel文件導(dǎo)出
批量處理4——java處理壓縮文件
Java知多少——相對(duì)路徑和絕對(duì)路徑
HTTP知多少——Content-disposition(文件下載)
如何對(duì)ZIP壓縮文件進(jìn)行處理?
1. 前端處理
<form id="batchForm" action="./XXX/batch">
<input type="file" name="KHSQ" id="batchFile" class="file-loading" style="display:none" onchange="$('#batchFilename').val($(this).val());" accept="aplication/zip"/>
<div class="input-group col-md-7">
<input id="batchFilename" class="form-control filename" type="text" ><a class="btn btn-default btn-sm input-group-addon" onclick="$('input[id=batchFile]').click();"><i class="fa fa-file-image-o"></i> 選擇文件</a>
</div>
</form>
<button id="batchButton" type="button" class="btn green" onclick="batchSubmit()">上傳</button>
即使我們使用了accept="aplication/zip"屬性。但用戶依舊可以選擇其他格式的文件,所有我們需要在JS中進(jìn)一步限制。
function batchSubmit() {
var self = $('#batchButton');
if (self.hasClass("disabled")) return;
var fileName = new String($('#batchFile').val());
if(fileName == null || fileName == '') {
layer.alert("請(qǐng)選擇文件!", {icon: 2});
return;
}
/*校驗(yàn)文件是否是ZIP格式*/
if(!fileName.endWith(".zip")) {
layer.alert("請(qǐng)選擇zip文件!", {icon: 2});
return;
}
/*使用formData完成文件上傳*/
var formData = new FormData();
formData.append("KHSQ", document.getElementById("batchFile").files[0]);
$.ajax({
url: "./XXX/upload",
type: "POST",
data: formData,
contentType: false,
processData: false,
success: function (data) {
}
});
2. 文件上傳
將前端上送的文件保存到服務(wù)器指定的路徑上。使用
multipartFile.transferTo(new File(batchPath));方法保存文件。
@RequestMapping("/upload")
@ResponseBody
public ResponseVo upload(HttpServletRequest request, HttpServletResponse response) {
ResponseVo responseVo = new ResponseVo();
try{
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
MultipartFile multipartFile = multipartRequest.getFile("KHSQ");
if(multipartFile!=null){
// 獲得文件名:
String originalfilename = multipartFile.getOriginalFilename();
//文件校驗(yàn)TODO
String batchPath ="XXX/originalfilename";
//創(chuàng)建目錄
File store = new File(batchPath);
if (!store.exists()) {
store.mkdirs();
}
/*保存文件*/
multipartFile.transferTo(new File(batchPath));
}
responseVo.setRetcode(200);
responseVo.setMessage("上傳成功");
}catch (Exception e){
responseVo.setRetcode(400);
responseVo.setMessage("上傳失敗 原因:" + e.getMessage());
logger.error("上傳失敗 原因:" + e);
}
return responseVo;
3. 文件處理
3.1 ZIP解壓縮
將ZIP文件解壓縮。本質(zhì)是重建一顆目錄樹。采用的是前序遍歷的方式。當(dāng)然我們采用
zipFile.getEntries();獲取Enumeration對(duì)象,進(jìn)行遍歷。需要注意的是,父級(jí)目錄可操縱子級(jí)目錄。我們采用一個(gè)list集合,將壓縮文件內(nèi)的第一層目錄保存到List中。
public static List<File> upZipFilesDic(String path) {
if(StringUtils.isBlank(path)){
return null;
}
File source=new File(path);
//獲取壓縮文件名
String descDir=path.substring(0,path.lastIndexOf("."));
//保存第一層文件或目錄
List<File> list = new ArrayList<>() ;
//此類用于從zip文件讀取條目。
ZipFile zipFile = null;
try {
//解決文件名中文亂碼
zipFile = new ZipFile(source , "GBK") ;
//遍歷ZIP壓縮文件的條目的枚舉
for(Enumeration entries = zipFile.getEntries(); entries.hasMoreElements() ; ){
//此類用于表示ZIP文件條目(目錄|文件)
ZipEntry entry = (ZipEntry)entries.nextElement() ;
//獲取條目的名稱
File file = new File(descDir + File.separator + entry.getName()) ;
//判斷條目是否是目錄
if( entry.isDirectory() ){
//File.getName獲取路徑名稱序列中的最后一個(gè)名字
String current = source.getName().substring(0,source.getName().lastIndexOf("."));
//判斷該目錄是否是壓縮文件的第一層目錄;即條目的父文件的名稱==壓縮文件的名字?
if(file.getParentFile().getName().equalsIgnoreCase(current)){
//將第一層目錄保存到List集合中。
list.add(file);
}
}else{
//條目是文件的情況下
//獲取條目的后綴名
String entityFileSuffix = file.getName().substring(file.getName().lastIndexOf(".")+1);
//獲取文件的父級(jí)目錄
File parent = file.getParentFile() ;
//創(chuàng)建目錄
if( !parent.exists() ){
parent.mkdirs() ;
}
//返回用于讀取指定zip文件條目?jī)?nèi)容的輸入流。
InputStream in = zipFile.getInputStream(entry);
//獲取文件輸出流,輸出到條目路徑
OutputStream out = new FileOutputStream(file) ;
int len ;
while( (len = in.read(_byte)) > 0){
out.write(_byte, 0, len);
}
if (null !=out){
out.close();
}
if (null !=in){
in.close();
}
//判斷后綴是否是xlsx,如果是的話,也保存到list中
if(entityFileSuffix.equalsIgnoreCase("xlsx")){
list.add(file);
}
}
}
}catch(IOException e){
logger.error(e);
}finally {
if(zipFile != null){
try{
zipFile.close();
}catch(IOException e){
logger.error(e);
}
}
}
return list;
}
處理完畢之后,只有壓縮文件內(nèi)的第一層目錄和.xlsx后綴的文件保存到list集合中,并且zip文件完成解壓。
3.2 處理解壓文件
文件解壓后,頂級(jí)目錄和Excel文件保存到了List中。需要單獨(dú)對(duì)List中目錄和文件進(jìn)行處理。
List<File> fileList = GzipUtil.upZipFilesDic(path);
//保存List中的目錄;
LinkedList<File> directoryList = new LinkedList<>();
//處理Excel文件
for (File file: fileList){
String fileSuffix= file.getName().substring(file.getName().lastIndexOf(".") + 1);
if(!fileSuffix.equals("xlsx")){
//將目錄保存到LinkedList中
directoryList.add(file);
}else{
//處理Excel文件
}
}
//File.listFiles()表示該抽象路徑名表示的目錄中的文件。
for (File file : directoryList.get(0).listFiles()){
//處理目錄下的文件或目錄
}
需要注意的一點(diǎn)是:
listFiles能夠獲取當(dāng)前文件夾下的所有文件和文件夾,如果文件夾A下還有文件D,那么D也在里面。
4. 壓縮文件的下載
壓縮文件的下載,還是設(shè)置響應(yīng)報(bào)文頭(Content-Disposition以及Content-Type)。
//文件路徑,response,下載的文件名
public static void downloadZip(String down, HttpServletResponse response,String fileName) {
try {
// 輸入流
InputStream fis = new BufferedInputStream(new FileInputStream(down));
byte[] buffer = new byte[fis.available()];
//將數(shù)據(jù)讀到buffer數(shù)組中
fis.read(buffer);
fis.close();
// 清空response
response.reset();
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
//以流的形式傳輸
response.setContentType("application/octet-stream");
//如果輸出的是中文名的文件,在此處就要用URLEncoder.encode方法進(jìn)行處理
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
//將數(shù)據(jù)寫到輸出流中
toClient.write(buffer);
toClient.close();
} catch (IOException ex) {
logger.error(ex.getMessage());
}
}