我必须将Excel文件映射到数据库值。鉴于Excel文件有很多行我使用https://github.com/monitorjbl/excel-streaming-reader,否则,使用Apache POI,我会收到内存错误。 这是旧代码,不适用于大文件:
/**
* Private method called from single and multiple file upload to retrieve the excel fields values
* This method works if THE EXCEL FILE IS WITHOUT empty row!!
* @param file
* @return
* @throws IOException
*/
private ExcelField[][] getExcelField(MultipartFile file) throws IOException{
try{
ArrayList<ArrayList<ExcelField>> valuesMatrix= new ArrayList<ArrayList<ExcelField>>();
Workbook wb = WorkbookFactory.create(file.getInputStream());
//Sheet to use
Sheet firstSheet = wb.getSheetAt(0);
//Assuming that the first row is without blank cell and it has the maximum number of columns.
//numCol IS NECESSARY BECAUSE IF THERE IS A EMPTY CELL AT THE LAST POSITION OF THE ROW THE GETLASTCELLNUM RETURN
//THE NUMBER OF ROWS WITHOUT THE LAST
int numCol=firstSheet.getRow(0).getLastCellNum();
int numRow=firstSheet.getPhysicalNumberOfRows();
for(int rw=0;rw<numRow;rw++) {
Row row=firstSheet.getRow(rw);
ArrayList<ExcelField> rowValues=new ArrayList<ExcelField>();
for(int cn=0; cn<numCol; cn++) {
Cell cell = row.getCell(cn, Row.CREATE_NULL_AS_BLANK);
rowValues.add(getCellValue(cell));
//Print into console the fields values
//System.out.print(getCellValue(cell).getValue()!=null?getCellValue(cell).getValue().toString():" null"+" ");
}
valuesMatrix.add(rowValues);
//System.out.println();
}
wb.close();
return convert2DimensionalArrayToMatrix(valuesMatrix);
} catch (EncryptedDocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
在Excel文件中有公式,日期,双精度,合并单元格等。在这一刻我有问题,只有新方法,公式和日期,我经常收到str或其他类型的未知异常。
Caused by: java.lang.UnsupportedOperationException: Unsupported cell type 'str'
at com.monitorjbl.xlsx.impl.StreamingCell.getCellType(StreamingCell.java:106)
at com.mkyong.services.FileServicesImpl.getCellValue(FileServicesImpl.java:193)
at com.mkyong.services.FileServicesImpl.getExcelFieldSpeedImproved(FileServicesImpl.java:176)
at com.mkyong.services.FileServicesImpl.singleFileOpen(FileServicesImpl.java:86)
相反,日期返回null值。我并不关心公式,但我感兴趣的只是因为我必须将它存储在数据库中。这是我的代码:
@Override
public Response<ExcelField[][]> singleFileOpen(MultipartFile file) throws FileEmptyException, FileUploadException{
if (!file.isEmpty()) {
try {
openedFile=file;
//Retrieve the fields values
// ExcelField[][] valuesMatrix=getExcelField(openedFile);
ExcelField[][] valuesMatrix=getExcelFieldSpeedImproved(openedFile);
// //return the Response with status ad excel fields
return new Response<ExcelField[][]>(HttpStatus.OK.value(),valuesMatrix);
} catch (Exception e) {
throw new FileUploadException("You failed to read " + openedFile.getOriginalFilename(), e);
}
} else {
throw new FileEmptyException("You failed to read" );
}
}
和主要方法:
private ExcelField[][] getExcelFieldSpeedImproved(MultipartFile file) throws IOException{
ArrayList<ArrayList<ExcelField>> valuesMatrix= new ArrayList<ArrayList<ExcelField>>();
InputStream is = file.getInputStream();
StreamingReader reader = 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)
.sheetIndex(0) // index of sheet to use (defaults to 0)
.read(is); // InputStream or File for XLSX file (required)
for (Row r : reader) {
ArrayList<ExcelField> rowValues=new ArrayList<ExcelField>();
for (Cell c : r) {
rowValues.add(getCellValue(c));
System.out.print((String)getCellValue(c).getValue()+" ");
}
valuesMatrix.add(rowValues);
System.out.println();
}
return convert2DimensionalArrayToMatrix(valuesMatrix);
}
和类型选择:
/**
* Retrieve the value in one excel field
* @param cell
* @return
*/
private ExcelField getCellValue(Cell cell) {
switch (cell.getCellType()) {
case Cell.CELL_TYPE_STRING:
return new ExcelField(ExcelTypeEnum.STRING,cell.getStringCellValue());
case Cell.CELL_TYPE_BOOLEAN:
return new ExcelField(ExcelTypeEnum.BOOLEAN,cell.getBooleanCellValue());
case Cell.CELL_TYPE_NUMERIC:
return new ExcelField(ExcelTypeEnum.NUMERIC,cell.getNumericCellValue());
case Cell.CELL_TYPE_ERROR:
return new ExcelField(ExcelTypeEnum.ERROR,cell.getErrorCellValue());
case Cell.CELL_TYPE_FORMULA:
return new ExcelField(ExcelTypeEnum.FORMULA,cell.getCachedFormulaResultType());
default:
return new ExcelField(ExcelTypeEnum.BLANK,null);
}
}
检索Excel值的最佳方法是什么?
更新:使用此代码我解决旧方法和日期和公式:
/**
* Retrieve the value in one excel field
* @param cell
* @return
*/
private ExcelField getCellValue(int cellType, Cell cell) {
switch (cellType) {
case Cell.CELL_TYPE_STRING:
return new ExcelField(ExcelTypeEnum.STRING,cell.getStringCellValue());
case Cell.CELL_TYPE_BOOLEAN:
return new ExcelField(ExcelTypeEnum.BOOLEAN,cell.getBooleanCellValue());
case Cell.CELL_TYPE_NUMERIC:
if (HSSFDateUtil.isCellDateFormatted(cell))
//SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
//System.out.print(dateFormat.format(cell.getDateCellValue()) + "\t\t");
return new ExcelField(ExcelTypeEnum.NUMERIC,cell.getDateCellValue());
return new ExcelField(ExcelTypeEnum.NUMERIC,cell.getNumericCellValue());
case Cell.CELL_TYPE_ERROR:
return new ExcelField(ExcelTypeEnum.ERROR,cell.getErrorCellValue());
case Cell.CELL_TYPE_FORMULA:
return getCellValue(cell.getCachedFormulaResultType(),cell);
case Cell.CELL_TYPE_BLANK:
return new ExcelField(ExcelTypeEnum.BLANK,null);
default:
return new ExcelField(ExcelTypeEnum.BLANK,cell.getStringCellValue());
}
}