package com.alibaba.excel.metadata.csv; import java.io.Closeable; import java.io.IOException; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.enums.NumericCellTypeEnum; import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.util.DateUtils; import com.alibaba.excel.util.ListUtils; import com.alibaba.excel.util.NumberDataFormatterUtils; import com.alibaba.excel.util.StringUtils; import lombok.Data; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVPrinter; import org.apache.poi.ss.usermodel.AutoFilter; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellRange; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Comment; import org.apache.poi.ss.usermodel.DataValidation; import org.apache.poi.ss.usermodel.DataValidationHelper; import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.Drawing; import org.apache.poi.ss.usermodel.Footer; import org.apache.poi.ss.usermodel.Header; import org.apache.poi.ss.usermodel.Hyperlink; import org.apache.poi.ss.usermodel.PrintSetup; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.SheetConditionalFormatting; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellAddress; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.PaneInformation; /** * csv sheet * * @author Jiaju Zhuang */ @Data public class CsvSheet implements Sheet, Closeable { /** * workbook */ private CsvWorkbook csvWorkbook; /** * output */ private Appendable out; /** * row cache */ private Integer rowCacheCount; /** * format */ public CSVFormat csvFormat; /** * last row index */ private Integer lastRowIndex; /** * row cache */ private List rowCache; /** * csv printer */ private CSVPrinter csvPrinter; public CsvSheet(CsvWorkbook csvWorkbook, Appendable out) { this.csvWorkbook = csvWorkbook; this.out = out; this.rowCacheCount = 3000; this.csvFormat = CSVFormat.DEFAULT; this.lastRowIndex = -1; } @Override public Row createRow(int rownum) { // Initialize the data when the row is first created initSheet(); lastRowIndex++; assert rownum == lastRowIndex : "csv create row must be in order."; printData(); CsvRow csvRow = new CsvRow(csvWorkbook, this, rownum); rowCache.add(csvRow); return csvRow; } private void initSheet() { if (csvPrinter != null) { return; } rowCache = ListUtils.newArrayListWithExpectedSize(rowCacheCount); try { csvPrinter = csvFormat.print(out); } catch (IOException e) { throw new ExcelGenerateException(e); } } @Override public void removeRow(Row row) { throw new UnsupportedOperationException("csv cannot move row."); } @Override public Row getRow(int rownum) { int actualRowIndex = rownum - (lastRowIndex - rowCache.size()) - 1; if (actualRowIndex < 0 || actualRowIndex > rowCache.size() - 1) { throw new UnsupportedOperationException("The current data does not exist or has been flushed to disk\n."); } return rowCache.get(actualRowIndex); } @Override public int getPhysicalNumberOfRows() { return lastRowIndex - rowCache.size(); } @Override public int getFirstRowNum() { if (lastRowIndex < 0) { return -1; } return 0; } @Override public int getLastRowNum() { return lastRowIndex; } @Override public void setColumnHidden(int columnIndex, boolean hidden) { } @Override public boolean isColumnHidden(int columnIndex) { return false; } @Override public void setRightToLeft(boolean value) { } @Override public boolean isRightToLeft() { return false; } @Override public void setColumnWidth(int columnIndex, int width) { } @Override public int getColumnWidth(int columnIndex) { return 0; } @Override public float getColumnWidthInPixels(int columnIndex) { return 0; } @Override public void setDefaultColumnWidth(int width) { } @Override public int getDefaultColumnWidth() { return 0; } @Override public short getDefaultRowHeight() { return 0; } @Override public float getDefaultRowHeightInPoints() { return 0; } @Override public void setDefaultRowHeight(short height) { } @Override public void setDefaultRowHeightInPoints(float height) { } @Override public CellStyle getColumnStyle(int column) { return null; } @Override public int addMergedRegion(CellRangeAddress region) { return 0; } @Override public int addMergedRegionUnsafe(CellRangeAddress region) { return 0; } @Override public void validateMergedRegions() { } @Override public void setVerticallyCenter(boolean value) { } @Override public void setHorizontallyCenter(boolean value) { } @Override public boolean getHorizontallyCenter() { return false; } @Override public boolean getVerticallyCenter() { return false; } @Override public void removeMergedRegion(int index) { } @Override public void removeMergedRegions(Collection indices) { } @Override public int getNumMergedRegions() { return 0; } @Override public CellRangeAddress getMergedRegion(int index) { return null; } @Override public List getMergedRegions() { return null; } @Override public Iterator rowIterator() { return (Iterator)(Iterator)rowCache.iterator(); } @Override public void setForceFormulaRecalculation(boolean value) { } @Override public boolean getForceFormulaRecalculation() { return false; } @Override public void setAutobreaks(boolean value) { } @Override public void setDisplayGuts(boolean value) { } @Override public void setDisplayZeros(boolean value) { } @Override public boolean isDisplayZeros() { return false; } @Override public void setFitToPage(boolean value) { } @Override public void setRowSumsBelow(boolean value) { } @Override public void setRowSumsRight(boolean value) { } @Override public boolean getAutobreaks() { return false; } @Override public boolean getDisplayGuts() { return false; } @Override public boolean getFitToPage() { return false; } @Override public boolean getRowSumsBelow() { return false; } @Override public boolean getRowSumsRight() { return false; } @Override public boolean isPrintGridlines() { return false; } @Override public void setPrintGridlines(boolean show) { } @Override public boolean isPrintRowAndColumnHeadings() { return false; } @Override public void setPrintRowAndColumnHeadings(boolean show) { } @Override public PrintSetup getPrintSetup() { return null; } @Override public Header getHeader() { return null; } @Override public Footer getFooter() { return null; } @Override public void setSelected(boolean value) { } @Override public double getMargin(short margin) { return 0; } @Override public void setMargin(short margin, double size) { } @Override public boolean getProtect() { return false; } @Override public void protectSheet(String password) { } @Override public boolean getScenarioProtect() { return false; } @Override public void setZoom(int scale) { } @Override public short getTopRow() { return 0; } @Override public short getLeftCol() { return 0; } @Override public void showInPane(int topRow, int leftCol) { } @Override public void shiftRows(int startRow, int endRow, int n) { } @Override public void shiftRows(int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight) { } @Override public void shiftColumns(int startColumn, int endColumn, int n) { } @Override public void createFreezePane(int colSplit, int rowSplit, int leftmostColumn, int topRow) { } @Override public void createFreezePane(int colSplit, int rowSplit) { } @Override public void createSplitPane(int xSplitPos, int ySplitPos, int leftmostColumn, int topRow, int activePane) { } @Override public PaneInformation getPaneInformation() { return null; } @Override public void setDisplayGridlines(boolean show) { } @Override public boolean isDisplayGridlines() { return false; } @Override public void setDisplayFormulas(boolean show) { } @Override public boolean isDisplayFormulas() { return false; } @Override public void setDisplayRowColHeadings(boolean show) { } @Override public boolean isDisplayRowColHeadings() { return false; } @Override public void setRowBreak(int row) { } @Override public boolean isRowBroken(int row) { return false; } @Override public void removeRowBreak(int row) { } @Override public int[] getRowBreaks() { return new int[0]; } @Override public int[] getColumnBreaks() { return new int[0]; } @Override public void setColumnBreak(int column) { } @Override public boolean isColumnBroken(int column) { return false; } @Override public void removeColumnBreak(int column) { } @Override public void setColumnGroupCollapsed(int columnNumber, boolean collapsed) { } @Override public void groupColumn(int fromColumn, int toColumn) { } @Override public void ungroupColumn(int fromColumn, int toColumn) { } @Override public void groupRow(int fromRow, int toRow) { } @Override public void ungroupRow(int fromRow, int toRow) { } @Override public void setRowGroupCollapsed(int row, boolean collapse) { } @Override public void setDefaultColumnStyle(int column, CellStyle style) { } @Override public void autoSizeColumn(int column) { } @Override public void autoSizeColumn(int column, boolean useMergedCells) { } @Override public Comment getCellComment(CellAddress ref) { return null; } @Override public Map getCellComments() { return null; } @Override public Drawing getDrawingPatriarch() { return null; } @Override public Drawing createDrawingPatriarch() { return null; } @Override public Workbook getWorkbook() { return csvWorkbook; } @Override public String getSheetName() { return null; } @Override public boolean isSelected() { return false; } @Override public CellRange setArrayFormula( String formula, CellRangeAddress range) { return null; } @Override public CellRange removeArrayFormula(Cell cell) { return null; } @Override public DataValidationHelper getDataValidationHelper() { return null; } @Override public List getDataValidations() { return null; } @Override public void addValidationData(DataValidation dataValidation) { } @Override public AutoFilter setAutoFilter(CellRangeAddress range) { return null; } @Override public SheetConditionalFormatting getSheetConditionalFormatting() { return null; } @Override public CellRangeAddress getRepeatingRows() { return null; } @Override public CellRangeAddress getRepeatingColumns() { return null; } @Override public void setRepeatingRows(CellRangeAddress rowRangeRef) { } @Override public void setRepeatingColumns(CellRangeAddress columnRangeRef) { } @Override public int getColumnOutlineLevel(int columnIndex) { return 0; } @Override public Hyperlink getHyperlink(int row, int column) { return null; } @Override public Hyperlink getHyperlink(CellAddress addr) { return null; } @Override public List getHyperlinkList() { return null; } @Override public CellAddress getActiveCell() { return null; } @Override public void setActiveCell(CellAddress address) { } @Override public Iterator iterator() { return rowIterator(); } @Override public void close() throws IOException { // Avoid empty sheets initSheet(); flushData(); csvPrinter.flush(); csvPrinter.close(); } public void printData() { if (rowCache.size() >= rowCacheCount) { flushData(); } } public void flushData() { try { for (CsvRow row : rowCache) { Iterator cellIterator = row.cellIterator(); int columnIndex = 0; while (cellIterator.hasNext()) { CsvCell csvCell = (CsvCell)cellIterator.next(); while (csvCell.getColumnIndex() > columnIndex++) { csvPrinter.print(null); } csvPrinter.print(buildCellValue(csvCell)); } csvPrinter.println(); } rowCache.clear(); } catch (IOException e) { throw new ExcelGenerateException(e); } } private String buildCellValue(CsvCell csvCell) { switch (csvCell.getCellType()) { case STRING: case ERROR: case FORMULA: return csvCell.getStringCellValue(); case NUMERIC: Short dataFormat = null; String dataFormatString = null; if (csvCell.getCellStyle() != null) { dataFormat = csvCell.getCellStyle().getDataFormat(); dataFormatString = csvCell.getCellStyle().getDataFormatString(); } if (csvCell.getNumericCellType() == NumericCellTypeEnum.DATE) { if (csvCell.getDateValue() == null) { return null; } // date if (dataFormat == null) { dataFormatString = DateUtils.defaultDateFormat; dataFormat = csvWorkbook.createDataFormat().getFormat(dataFormatString); } if (dataFormatString == null) { dataFormatString = csvWorkbook.createDataFormat().getFormat(dataFormat); } return NumberDataFormatterUtils.format( DateUtil.getExcelDate(csvCell.getDateValue(), csvWorkbook.getUse1904windowing()), dataFormat, dataFormatString, csvWorkbook.getUse1904windowing(), csvWorkbook.getLocale(), csvWorkbook.getUseScientificFormat()); } else { if (csvCell.getNumberValue() == null) { return null; } //number if (dataFormat == null) { dataFormat = BuiltinFormats.GENERAL; dataFormatString = csvWorkbook.createDataFormat().getFormat(dataFormat); } return NumberDataFormatterUtils.format(csvCell.getNumericCellValue(), dataFormat, dataFormatString, csvWorkbook.getUse1904windowing(), csvWorkbook.getLocale(), csvWorkbook.getUseScientificFormat()); } case BOOLEAN: return csvCell.getBooleanValue().toString(); case BLANK: return StringUtils.EMPTY; default: return null; } } }