昨晚我正在床上睡得著著的,突然來了一條簡訊。 啥,線上MySQL死鎖了,我趕緊登錄線上系統,查看業務日誌。 ...
excel文件校驗
工作中,經常存在excel文件的導入導出的相關工作,因此正確的文件格式校驗成為必須。
不合適的文件校驗方式會導致非法文件跳過校驗,從而產生不必要的麻煩。
比如,通過文件尾碼名的方式進行校驗,這種方式其實是存在問題的,因為尾碼名可自定義。
正確的校驗方式,則應該根據文件流相關屬性進行判斷。
下麵,根據個人工作和參考其他人的經驗,逐一進行說明。
一、excel文件兩種格式
正常excel存在兩種常見的格式,分別是 2003 和 2007格式,
其文件尾碼名分別是.xls
和 .xlsx
。2007版相對與2003版最大的變動是它的文件格式,使用xml語言的壓縮方式,更規範也更適合新的需求。
兩種格式,都仍有人在同時使用,我個人推薦 2007 格式。
序號 | 名稱 | 尾碼名 | 文件格式 | 相容性 |
---|---|---|---|---|
1 | 2003 | .xls | bin | 不向上相容 |
2 | 2007 | .xlsx | xml | 向下相容 |
二、 excel文件校驗
2.1 文件尾碼名校驗
這種方式其實也可以用來校驗,但只屬於初驗。用戶通過修改文件尾碼名,可以繞過這種校驗方式。
比如,demo.txt文件,我們可以強制修改文件尾碼名,讓它變成demo.xls文件。
通常校驗的方式是文件名尾碼截取,只截取最後一個.
字元後的內容, 或者使用正則表達式。
2.2 apache poi 3.xx 版本校驗excel
處理excel的開源jar包有兩個,一個是jxl
, 一個是 apache poi
,現在主流的是後者。
apache poi 3.xx 版本校驗excel跟 4.xx版本存在不同,這裡僅就本人遇到的情況進行說明。
這裡3.xx版本使用的是3.10.1
版本。
-
引入相關依賴
這裡引入了
httpcomponents
jar包,為了進行文件類型File -> MultipartFile
的轉換,畢竟web項目經常使用的是MultipartFile
格式的入參文件。dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.10.1</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.10.1</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.9</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.19</version> <scope>compile</scope> </dependency>
-
校驗方法
package com.lunyu.tools.poi.excel; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PushbackInputStream; import org.apache.http.entity.ContentType; import org.apache.poi.POIXMLDocument; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; /** * Excel 校驗 * @author lunyu * @since 2022/6/25 */ public class ExcelPoi3Main { public static void main(String[] args) throws IOException { File file = new File("poi/excel/demo.xls"); FileInputStream fileInputStream = new FileInputStream(file); //轉成MultipartFile MultipartFile mf = new MockMultipartFile(file.getName(), file.getName(), ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream); // 執行校驗 boolean checkResult = checkExcelValid(mf); System.out.println("excel = " + file.getName() + "校驗結果: " + checkResult); // TODO: 進一步要做的操作 } /** * 檢驗excel合法性 * @param mf * @return * @throws IOException */ private static boolean checkExcelValid(MultipartFile mf) throws IOException { InputStream is = mf.getInputStream(); if(! is.markSupported()) { is = new PushbackInputStream(is, 8); } // 校驗excel格式 return POIFSFileSystem.hasPOIFSHeader(is) || POIXMLDocument.hasOOXMLHeader(is); } }
需要進行說明的是,在3.xx 版本中,
POIFSFileSystem.hasPOIFSHeader(InputStream is)
方法用於校驗excel文件是否符合xls格式,而POIXMLDocument.hasOOXMLHeader(InputStream is)
方法則用於校驗excel文件是否符合xlsx格式。
2.3 apache poi 4.xx 版本校驗excel
同上,我們先引入需要的jar包。
-
引入相關依賴
dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.9</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.19</version> <scope>compile</scope> </dependency>
-
編寫校驗方法
package com.lunyu.tools.poi.excel; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.http.entity.ContentType; import org.apache.poi.EmptyFileException; import org.apache.poi.poifs.filesystem.FileMagic; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; /** * Excel 校驗 * @author lunyu * @since 2022/6/25 */ public class ExcelPoi4Main { public static void main(String[] args) throws IOException { File file = new File("poi/excel/demo.txt"); FileInputStream fileInputStream = new FileInputStream(file); //轉成MultipartFile MultipartFile mf = new MockMultipartFile(file.getName(), file.getName(), ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream); // 執行校驗 boolean checkResult = checkExcelValid(mf); System.out.println("excel = " + file.getName() + "校驗結果: " + checkResult); // TODO: 進一步要做的操作 } /** * 檢驗excel合法性 * @param mf * @return * @throws IOException */ private static boolean checkExcelValid(MultipartFile mf) throws IOException { InputStream is = mf.getInputStream(); is = FileMagic.prepareToCheckMagic(is); FileMagic fm; try { fm = FileMagic.valueOf(is); }catch (EmptyFileException e) { System.out.println(e.getMessage()); return false; } return FileMagic.OLE2.equals(fm) || FileMagic.OOXML.equals(fm); } }
4.xx 版本中,方法
FileMagic.OLE2.equals(FileMagic fm)
用於校驗excel是否是xls
格式,方法FileMagic.OOXML.equals(FileMagic fm)
用於校驗excel是否是xlsx
格式。