2013-01-25 126 views
15

有沒有辦法在Apache POI中確定MS Office Excel文件類型?我需要知道什麼格式的Excel文件:在Excel '97(-2007)(.xls)或Excel 2007 OOXML(.xlsx)中。使用Apache POI確定MS Excel文件類型

我想我可以做這樣的事情:

int type = PoiTypeHelper.getType(file); 
switch (type) { 
case PoiType.EXCEL_1997_2007: 
    ... 
    break; 
case PoiType.EXCEL_2007: 
    ... 
    break; 
default: 
    ... 
} 

感謝。

+1

爲什麼你需要知道前面?你不能只使用WorkbookFactory並讓它爲你創建合適的類型嗎? – Gagravarr

+0

這也是一個很好的變體,謝謝。 –

回答

35

推進到一個答案評論...

如果你打算做與文件一些特別的東西,然後rjokelai's answer是做它的方式。但是,如果你打算使用HSSF/XSSF/Common SS用戶模型,那麼讓POI爲你做這件事更簡單,並且使用WorkbookFactory來檢測並打開你的類型。你會做這樣的事情:

Workbook wb = WorkbookFactory.create(new File("something.xls")); 

Workbook wb = WorkbookFactory.create(request.getInputStream()); 

然後,如果你需要做一些特別的東西,測試,如果它是一個HSSFWorkbookXSSFWorkbook。打開文件時,use a File rather than an InputStream if possible可以加快速度並節省內存。

如果您不知道您的文件是什麼,請使用Apache Tika來執行檢測 - 它可以爲您檢測大量不同的文件格式。

+0

Thanks Gagravarr ! –

21

您可以使用:

// For .xlsx 
POIXMLDocument.hasOOXMLHeader(new BufferedInputStream(new FileInputStream(file))); 

// For .xls 
POIFSFileSystem.hasPOIFSHeader(new BufferedInputStream(new FileInputStream(file))); 

這些基本上是,WorkbookFactory#create(InputStream)用來判斷類型

請注意方法,這兩種方法僅支持流支持「標記」功能(或PushBackInputStream) ,所以不支持簡單的FileInputStream。使用BufferedInputStream作爲包裝。出於這個原因,在檢測之後,您可以簡單地重新使用該流,因爲它將被重新設置爲起點。

+1

謝謝。當您使用基於低級別基於事件的只讀訪問來處理大型Excel文件時,這是檢測文件類型的唯一方法。 – SWilk

+1

添加了僅可使用「標記」支持流的信息。更新的代碼示例。 –

+0

方法'hasOOXMLHeader'在類POIXMLDocument中被描述,在類[DocumentFactoryHelper](https://poi.apache.org/apidocs/org/apache/poi/poifs/filesystem/DocumentFactoryHelper.html)中使用它 – KAD

1

基礎上的lib實施org.apache.poi.ss.usermodel.WorkbookFactory#create(java.io.InputStream)

我們可以模仿WorkbookFactory的邏輯,去除不相關的位,返回文件類型來代替。

public static TYPE fileType(File file) { 
    try (
      InputStream inp = new FileInputStream(file) 
    ) { 
     if (!(inp).markSupported()) { 
      return getNotMarkSupportFileType(file); 
     } 
     return getType(inp); 
    } catch (IOException e) { 
     LOGGER.error("Analyse FileType Problem.", e); 
     return TYPE.INVALID; 
    } 
} 

private static TYPE getNotMarkSupportFileType(File file) throws IOException { 
    try (
      InputStream inp = new PushbackInputStream(new FileInputStream(file), 8) 
    ) { 
     return getType(inp); 
    } 
} 

private static TYPE getType(InputStream inp) throws IOException { 
    byte[] header8 = IOUtils.peekFirst8Bytes(inp); 
    if (NPOIFSFileSystem.hasPOIFSHeader(header8)) { 
     NPOIFSFileSystem fs = new NPOIFSFileSystem(inp); 
     return fileType(fs); 
    } else if (DocumentFactoryHelper.hasOOXMLHeader(inp)) { 
     return TYPE.XSSF_WORKBOOK; 
    } 
    return TYPE.INVALID; 
} 

private static TYPE fileType(NPOIFSFileSystem fs) { 
    DirectoryNode root = fs.getRoot(); 
    if (root.hasEntry("EncryptedPackage")) { 
     return TYPE.XSSF_WORKBOOK; 
    } 
    return TYPE.HSSF_WORKBOOK; 

} 

public enum TYPE { 
    HSSF_WORKBOOK, XSSF_WORKBOOK, INVALID 
}