LINUX.ORG.RU

Java, чтение Excel-файлов - посоветуйте библу

 ,


0

2

Сейчас использую


        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.16</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.16</version>
        </dependency>

вот такой класс-читальщик, который нашел на просторах инета

import org.apache.poi.ss.usermodel.*;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Created by bvn13 on 01.07.2017.
 */
public class ExcelReader {

    public static List<List<String>> readSpreadSheet(InputStream inputStream, Integer sheetNum) {
        Workbook workBook = null;
        try {
            workBook = WorkbookFactory.create(inputStream);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        Sheet sheet = workBook.getSheetAt(sheetNum);
        List<List<String>> rowHolder = new ArrayList<List<String>>();
        int cellNum = sheet.getRow(1).getLastCellNum();

        for (int i = 0; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            List<String> cellHolder = new ArrayList<String>();

            for (int j = 0; j < row.getLastCellNum(); j++) {
                Cell cell = row.getCell(j);
                String cellValue = parseCellValue(workBook, cell);
                cellHolder.add(cellValue);
            }

            //add empty cells to the end if required
            while (cellHolder.size() < cellNum) {
                cellHolder.add(null);
            }
            rowHolder.add(cellHolder);
        }
        return rowHolder;
    }

    private static String parseCellValue(Workbook workBook, Cell cell) {
        FormulaEvaluator evaluator = workBook.getCreationHelper().createFormulaEvaluator();
        String cellValue = null;
        if (cell != null) {
            switch (cell.getCellTypeEnum()) {
                case STRING:
                    cellValue = cell.getRichStringCellValue().getString();
                    break;
                case NUMERIC:
                    if (DateUtil.isCellDateFormatted(cell)) {
                        cellValue = cell.getDateCellValue().toString();
                    } else {
                        cellValue = new Double(cell.getNumericCellValue()).toString();
                    }
                    break;
                case BOOLEAN:
                    cellValue = new Boolean(cell.getBooleanCellValue()).toString();
                    break;
                case FORMULA:
                    cellValue = evaluator.evaluate(cell).formatAsString();
                    break;
            }
        }
        return cellValue;
    }

    public static List<List<String>> readSpreadSheetWOnull(InputStream inputStream, Integer sheetNumber) {
        Workbook workBook = null;
        try {
            workBook = WorkbookFactory.create(inputStream);
            Sheet sheet = workBook.getSheetAt(sheetNumber);

            Iterator<Row> rowIter = sheet.rowIterator();

            List<List<String>> rowHolder = new ArrayList<List<String>>();
            while (rowIter.hasNext()) {
                Row row = (Row) rowIter.next();
                Iterator<Cell> cellIter = row.cellIterator();

                List<String> cellHolder = new ArrayList<String>();
                while (cellIter.hasNext()) {
                    Cell cell = (Cell) cellIter.next();
                    String cellValue = parseCellValue(workBook, cell);
                    cellHolder.add(cellValue);
                }
                rowHolder.add(cellHolder);
            }
            return rowHolder;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static List<List<String>> readSpreadSheetWOnull(InputStream inputStream) {
        return readSpreadSheetWOnull(inputStream, 0);
    }
    public static List<List<String>> readSpreadSheet(InputStream inputStream) {
        return readSpreadSheet(inputStream, 0);
    }
}

Если подсунуть 10-меговый файл, то даже на моем i7 8Gb вылетает с ошибкой:

Exception in thread "ru.bvn13.priceprocessor.workers.PriceLoaderFromFileWorker" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl.getNodeObject(DeferredDocumentImpl.java:1017)
	at com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl.synchronizeChildren(DeferredDocumentImpl.java:1755)
	at com.sun.org.apache.xerces.internal.dom.DeferredElementNSImpl.synchronizeChildren(DeferredElementNSImpl.java:158)
	at com.sun.org.apache.xerces.internal.dom.ParentNode.getFirstChild(ParentNode.java:229)
	at org.apache.xmlbeans.impl.store.Locale.loadNodeChildren(Locale.java:1402)
	at org.apache.xmlbeans.impl.store.Locale.loadNode(Locale.java:1445)
	at org.apache.xmlbeans.impl.store.Locale.loadNodeChildren(Locale.java:1403)
	at org.apache.xmlbeans.impl.store.Locale.loadNode(Locale.java:1445)
	at org.apache.xmlbeans.impl.store.Locale.loadNodeChildren(Locale.java:1403)
	at org.apache.xmlbeans.impl.store.Locale.loadNode(Locale.java:1445)
	at org.apache.xmlbeans.impl.store.Locale.loadNodeChildren(Locale.java:1403)
	at org.apache.xmlbeans.impl.store.Locale.loadNode(Locale.java:1445)
	at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1385)
	at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1370)
	at org.apache.xmlbeans.impl.schema.SchemaTypeLoaderBase.parse(SchemaTypeLoaderBase.java:370)
	at org.apache.poi.POIXMLTypeLoader.parse(POIXMLTypeLoader.java:144)
	at org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument$Factory.parse(Unknown Source)
	at org.apache.poi.xssf.usermodel.XSSFSheet.read(XSSFSheet.java:183)
	at org.apache.poi.xssf.usermodel.XSSFSheet.onDocumentRead(XSSFSheet.java:175)
	at org.apache.poi.xssf.usermodel.XSSFWorkbook.parseSheet(XSSFWorkbook.java:438)
	at org.apache.poi.xssf.usermodel.XSSFWorkbook.onDocumentRead(XSSFWorkbook.java:403)
	at org.apache.poi.POIXMLDocument.load(POIXMLDocument.java:190)
	at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:266)
	at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:185)
	at org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:144)
	at ru.bvn13.priceprocessor.utils.ExcelReader.readSpreadSheet(ExcelReader.java:18)
	at ru.bvn13.priceprocessor.utils.ExcelReader.readSpreadSheet(ExcelReader.java:102)
	at ru.bvn13.priceprocessor.workers.PriceLoaderFromFileWorker.readFileNewExcelFormat(PriceLoaderFromFileWorker.java:409)
	at ru.bvn13.priceprocessor.workers.PriceLoaderFromFileWorker.loadFile(PriceLoaderFromFileWorker.java:294)
	at ru.bvn13.priceprocessor.workers.PriceLoaderFromFileWorker.startLoadingFile(PriceLoaderFromFileWorker.java:206)
	at ru.bvn13.priceprocessor.workers.PriceLoaderFromFileWorker.job(PriceLoaderFromFileWorker.java:96)
	at ru.bvn13.priceprocessor.workers.AbstractWorker.run(AbstractWorker.java:52)

А есть что-то менее прожорливое, чтобы читать?

★★★★★

Ответ на: комментарий от vtVitus

https://yadi.sk/d/7N-lbmgA3MGqCM

код:

import com.monitorjbl.xlsx.StreamingReader;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        if (args.length == 0) {
            System.out.println("USAGE: this_app [file.xls]");
            return;
        }

        System.out.println("Try to load: "+args[0]);
        InputStream is = null;
        try {
            is = new FileInputStream(new File(args[0]));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return;
        }
        Workbook workbook = StreamingReader.builder()
                .rowCacheSize(100)    // number of rows to keep in memory (defaults to 10)
                .bufferSize(4096)     // buffer size to use when reading InputStream to file (defaults to 1024)
                .open(is);            // InputStream or File for XLSX file (required)

        Integer rowsCount = 0;
        for (Sheet sheet : workbook){
            System.out.println(sheet.getSheetName());
            for (Row r : sheet) {
                rowsCount++;
            }
        }

        System.out.println("TOTAL ROWS: "+rowsCount);
    }
}
[/java]

Проект тут: https://yadi.sk/d/QTMdy5OR3MGrmZ

Ошибка стандартная:

Try to load: C:\dev\my\TestExcel\target\ARMTEK_MOSKOV.xlsx
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Лист1
Exception in thread "main" java.lang.NumberFormatException: For input string: "1 "
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:580)
	at java.lang.Integer.parseInt(Integer.java:615)
	at com.monitorjbl.xlsx.impl.StreamingSheetReader.unformattedContents(StreamingSheetReader.java:316)
	at com.monitorjbl.xlsx.impl.StreamingSheetReader.handleEvent(StreamingSheetReader.java:184)
	at com.monitorjbl.xlsx.impl.StreamingSheetReader.getRow(StreamingSheetReader.java:76)
	at com.monitorjbl.xlsx.impl.StreamingSheetReader.access$100(StreamingSheetReader.java:37)
	at com.monitorjbl.xlsx.impl.StreamingSheetReader$StreamingRowIterator.hasNext(StreamingSheetReader.java:370)
	at com.monitorjbl.xlsx.impl.StreamingSheetReader$StreamingRowIterator.<init>(StreamingSheetReader.java:364)
	at com.monitorjbl.xlsx.impl.StreamingSheetReader.iterator(StreamingSheetReader.java:336)
	at com.monitorjbl.xlsx.impl.StreamingSheet.iterator(StreamingSheet.java:49)
	at ru.bvn13.test.App.main(App.java:43)
bvn13 ★★★★★
() автор топика
Ответ на: комментарий от vtVitus

Работает получение Raw данных из ячеек String cellValue = ((XSSFCell) cell).getRawValue();. Но все равно читается неправильно. https://i.imgur.com/OJ3UaUI.png

bvn13 ★★★★★
() автор топика
Ответ на: комментарий от bvn13

у файла порушены индексы на таблицу строк (sharedStrings.xml) Исправить можно двумя способами либо пересохранить в экселе. Либо пропатчить xlsx-streamer метод StreamingSheetReader.unformattedContents int idx = Integer.parseInt(_lastContents.trim());

есть мнение, что генерят данный файл руками через кривой софт.

vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 2)
Ответ на: комментарий от vtVitus

Контрибутор сказал спасибо, мол, баги давно репортят, патча не было. Просил тест сварганить.

bvn13 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.