Определить тип файла MS Excel с помощью Apache POI - программирование
Подтвердить что ты не робот

Определить тип файла MS Excel с помощью Apache POI

Есть ли способ определить тип файла MS Office Excel в Apache POI? Мне нужно знать, в каком формате находится файл Excel: в Excel '97 (-2007) (.xls) или Excel 2007 OOXML (.xlsx).

Я полагаю, я мог бы сделать что-то вроде этого:

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

Спасибо.

4b9b3361

Ответ 1

Продвижение комментария к ответу...

Если вы собираетесь делать что-то особенное с файлами, то rjokelai answer - это способ сделать это.

Однако, если вы собираетесь использовать HSSF/XSSF/Common SS usermodel, тогда гораздо проще использовать POI для вас и использовать WorkbookFactory, чтобы тип был обнаружен и открыт для вас. Вы бы сделали что-то вроде:

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

или

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

Затем, если вам нужно сделать что-то особенное, проверьте, есть ли это HSSFWorkbook или XSSFWorkbook. При открытии файла используйте файл, а не InputStream, если это возможно, чтобы ускорить работу и сохранить память.

Если вы вообще не знаете, что такое ваш файл, используйте Apache Tika для обнаружения - он может обнаружить огромное количество различные форматы файлов для вас.

Ответ 2

Вы можете использовать:

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

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

Это, по существу, методы, которые использует WorkbookFactory#create(InputStream) для определения типа

Обратите внимание, что оба метода поддерживают только потоки, поддерживающие функцию "mark" (или PushBackInputStream), поэтому простой FileInputStream не поддерживается. Используйте BufferedInputStream в качестве обертки. По этой причине после обнаружения вы можете просто повторно использовать поток, так как он будет сброшен до начальной точки.

Ответ 3

На основе реализации 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
}