ps: 以下功能針對版本 4.0+
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.0</version> </dependency>
poi也有兩個不同的jar包,分別是處理excel2003和excel2007+的,對應的是poi和poi-ooxml。
畢竟poi-ooxml是poi的升級版本,處理的單頁數據量也是百萬級別的,所以我們選擇的也是poi-ooxml
1.如何創建一個新的工作簿
1 Workbook wb = new HSSFWorkbook(); 2 ... 3 try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { 4 wb.write(fileOut); 5 } 6 Workbook wb = new XSSFWorkbook(); 7 ... 8 try (OutputStream fileOut = new FileOutputStream("workbook.xlsx")) { 9 wb.write(fileOut); 10 } 11
2.如何建立工作表
Workbook wb = new HSSFWorkbook(); // or new XSSFWorkbook(); Sheet sheet1 = wb.createSheet("new sheet"); Sheet sheet2 = wb.createSheet("second sheet"); //請注意,工作表名稱為Excel不得超過31個字符 //,且不得包含以下任何字符: // 0x0000 // 0x0003 //冒號(:) //反斜杠(\) //星號(*) //問號(?) //正斜杠(/) //打開方括號([) //右方括號(]) //您可以使用org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)} //為了安全地創建有效名稱,此實用程序將無效字符替換為空格('') String safeName = WorkbookUtil.createSafeSheetName("[O'Brien's sales*?]"); // returns " O'Brien's sales " Sheet sheet3 = wb.createSheet(safeName); try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); }
3.如何創建細胞
Workbook wb = new HSSFWorkbook(); //Workbook wb = new XSSFWorkbook(); CreationHelper createHelper = wb.getCreationHelper(); Sheet sheet = wb.createSheet("new sheet"); //創建一行並在其中放入一些單元格。行從0開始。 Row row = sheet.createRow(0); //創建一個單元格並在其中放置一個值。 Cell cell = row.createCell(0); cell.setCellValue(1); //或一行完成。 row.createCell(1).setCellValue(1.2); row.createCell(2).setCellValue( createHelper.createRichTextString("This is a string")); row.createCell(3).setCellValue(true); //將輸出寫入文件 try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); }
4.如何創建日期單元
Workbook wb = new HSSFWorkbook(); //Workbook wb = new XSSFWorkbook(); CreationHelper createHelper = wb.getCreationHelper(); Sheet sheet = wb.createSheet("new sheet"); //創建一行並在其中放入一些單元格。行從0開始。 Row row = sheet.createRow(0); //創建一個單元格並在其中放置一個日期值。第一個單元格未設置樣式 //作為日期。 Cell cell = row.createCell(0); cell.setCellValue(new Date()); //我們將第二個單元格設置為日期(和時間)。重要的是要 //從工作簿中創建新的單元格樣式,否則您可以結束 //修改內置樣式並不僅影響此單元格,而且影響其他單元格。 CellStyle cellStyle = wb.createCellStyle(); cellStyle.setDataFormat( createHelper.createDataFormat().getFormat("m/d/yy h:mm")); cell = row.createCell(1); cell.setCellValue(new Date()); cell.setCellStyle(cellStyle); //您也可以將日期設置為java.util.Calendar cell = row.createCell(2); cell.setCellValue(Calendar.getInstance()); cell.setCellStyle(cellStyle); //將輸出寫入文件 try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); }
5.處理不同類型的細胞
Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet("new sheet"); Row row = sheet.createRow(2); row.createCell(0).setCellValue(1.1); row.createCell(1).setCellValue(new Date()); row.createCell(2).setCellValue(Calendar.getInstance()); row.createCell(3).setCellValue("a string"); row.createCell(4).setCellValue(true); row.createCell(5).setCellType(CellType.ERROR); //將輸出寫入文件 try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); }
6.遍歷行和單元格
有時,您只想遍歷工作簿中的所有工作表,工作表中的所有行或行中的所有單元格。這可以通過簡單的for循環來實現。
通過調用workbook.sheetIterator(), sheet.rowIterator()和row.cellIterator()或隱式使用for-each循環,可以使用這些迭代器。請注意,rowIterator和cellIterator遍歷已創建的行或單元格,跳過空的行和單元格。
for (Sheet sheet : wb ) { for (Row row : sheet) { for (Cell cell : row) { // 填充內容 } } }
遍歷單元格,控制丟失/空白的單元格
在某些情況下,進行迭代時,您需要完全控制如何處理丟失或空白的行和單元格,並且需要確保訪問每個單元格,而不僅僅是訪問文件中定義的那些單元格。(CellIterator將僅返回文件中定義的單元格,這些單元格在很大程度上具有值或樣式,但取決於Excel)。
在這種情況下,應該獲取一行的第一列和最后一列信息,然后調用getCell(int,MissingCellPolicy) 來獲取單元格。使用 MissingCellPolicy 控制空白或空單元格的處理方式。
//確定要處理的行 int rowStart = Math.min(15, sheet.getFirstRowNum()); int rowEnd = Math.max(1400, sheet.getLastRowNum()); for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) { Row r = sheet.getRow(rowNum); if (r == null) { //這整行是空的 //需要處理 continue; } int lastColumn = Math.max(r.getLastCellNum(), MY_MINIMUM_COLUMN_COUNT); for (int cn = 0; cn < lastColumn; cn++) { Cell c = r.getCell(cn, Row.RETURN_BLANK_AS_NULL); if (c == null) { //電子表格在此單元格中為空 } else { //對單元格內容進行一些有用的操作 } } }
7.獲取單元格內容
要獲取單元格的內容,您首先需要知道它是哪種單元格(例如,將字符串單元格作為其數字內容將獲得NumberFormatException)。因此,您將需要打開單元格的類型,然后為該單元格調用適當的getter。
在下面的代碼中,我們遍歷一張紙中的每個單元格,打印出單元格的引用(例如A3),然后打印出單元格的內容。
// import org.apache.poi.ss.usermodel.*; DataFormatter formatter = new DataFormatter(); Sheet sheet1 = wb.getSheetAt(0); for (Row row : sheet1) { for (Cell cell : row) { CellReference cellRef = new CellReference(row.getRowNum(), cell.getColumnIndex()); System.out.print(cellRef.formatAsString()); System.out.print(" - "); //通過獲取單元格值並應用任何數據格式(日期,0.00、1.23e9,$ 1.23等)來獲取顯示在單元格中的文本 String text = formatter.formatCellValue(cell); System.out.println(text); //或者,獲取值並自行格式化 switch (cell.getCellType()) { case CellType.STRING: System.out.println(cell.getRichStringCellValue().getString()); break; case CellType.NUMERIC: if (DateUtil.isCellDateFormatted(cell)) { System.out.println(cell.getDateCellValue()); } else { System.out.println(cell.getNumericCellValue()); } break; case CellType.BOOLEAN: System.out.println(cell.getBooleanCellValue()); break; case CellType.FORMULA: System.out.println(cell.getCellFormula()); break; case CellType.BLANK: System.out.println(); break; default: System.out.println(); } } }
8.文字提取
對於大多數文本提取要求,標准ExcelExtractor類應提供所需的全部內容。
try (InputStream inp = new FileInputStream("workbook.xls")) { HSSFWorkbook wb = new HSSFWorkbook(new POIFSFileSystem(inp)); ExcelExtractor extractor = new ExcelExtractor(wb); extractor.setFormulasNotResults(true); extractor.setIncludeSheetNames(false); String text = extractor.getText(); wb.close(); }
對於非常精美的文本提取,XLS到CSV等,請查看 /src/examples/src/org/apache/poi/examples/hssf/eventusermodel/XLS2CSVmra.java
9.文件與InputStreams
當打開工作簿(.xls HSSFWorkbook或.xlsx XSSFWorkbook)時,可以從File 或InputStream加載工作簿。使用File對象可以減少內存消耗,而InputStream需要更多內存,因為它必須緩沖整個文件。
如果使用WorkbookFactory,則使用其中一個非常容易:
//使用文件
Workbook wb = WorkbookFactory.create(new File("MyExcel.xls"));
//使用InputStream,需要更多的內存
Workbook wb = WorkbookFactory.create(new FileInputStream("MyExcel.xlsx"));
如果直接使用HSSFWorkbook或XSSFWorkbook,通常應遍歷POIFSFileSystem或 OPCPackage,以完全控制生命周期(包括完成后關閉文件):
// HSSFWorkbook,文件
POIFSFileSystem fs = new POIFSFileSystem(new File("file.xls"));
HSSFWorkbook wb = new HSSFWorkbook(fs.getRoot(), true); .... fs.close(); // HSSFWorkbook InputStream需要更多內存 POIFSFileSystem fs = new POIFSFileSystem(myInputStream); HSSFWorkbook wb = new HSSFWorkbook(fs.getRoot(), true); // XSSFWorkbook,文件 OPCPackage pkg = OPCPackage.open(new File("file.xlsx")); XSSFWorkbook wb = new XSSFWorkbook(pkg); .... pkg.close(); // XSSFWorkbook InputStream需要更多內存 OPCPackage pkg = OPCPackage.open(myInputStream); XSSFWorkbook wb = new XSSFWorkbook(pkg); .... pkg.close();
10.對齊細胞
public static void main(String[] args) throws Exception { Workbook wb = new XSSFWorkbook(); //or new HSSFWorkbook(); Sheet sheet = wb.createSheet(); Row row = sheet.createRow(2); row.setHeightInPoints(30); createCell(wb, row, 0, HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM); createCell(wb, row, 1, HorizontalAlignment.CENTER_SELECTION, VerticalAlignment.BOTTOM); createCell(wb, row, 2, HorizontalAlignment.FILL, VerticalAlignment.CENTER); createCell(wb, row, 3, HorizontalAlignment.GENERAL, VerticalAlignment.CENTER); createCell(wb, row, 4, HorizontalAlignment.JUSTIFY, VerticalAlignment.JUSTIFY); createCell(wb, row, 5, HorizontalAlignment.LEFT, VerticalAlignment.TOP); createCell(wb, row, 6, HorizontalAlignment.RIGHT, VerticalAlignment.TOP); //將輸出寫入文件 try (OutputStream fileOut = new FileOutputStream("xssf-align.xlsx")) { wb.write(fileOut); } wb.close(); } / ** * 創建一個單元格並以某種方式對齊它。 * * @param wb工作簿 * @param row在其中創建單元格的行 * @param列在其中創建單元格的列號 * @param將單元格的水平對齊方式對齊。 * @param valign單元格的垂直對齊方式。 * / private static void createCell(Workbook wb, Row row, int column, HorizontalAlignment halign, VerticalAlignment valign) { Cell cell = row.createCell(column); cell.setCellValue("Align It"); CellStyle cellStyle = wb.createCellStyle(); cellStyle.setAlignment(halign); cellStyle.setVerticalAlignment(valign); cell.setCellStyle(cellStyle); }
11.邊界處理
Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet("new sheet"); //創建一行並在其中放入一些單元格。行從0開始。 Row row = sheet.createRow(1); //創建一個單元格並在其中放置一個值。 Cell cell = row.createCell(1); cell.setCellValue(4); //用周圍的邊框設置單元格的樣式。 CellStyle style = wb.createCellStyle(); style.setBorderBottom(BorderStyle.THIN); style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); style.setBorderLeft(BorderStyle.THIN); style.setLeftBorderColor(IndexedColors.GREEN.getIndex()); style.setBorderRight(BorderStyle.THIN); style.setRightBorderColor(IndexedColors.BLUE.getIndex()); style.setBorderTop(BorderStyle.MEDIUM_DASHED); style.setTopBorderColor(IndexedColors.BLACK.getIndex()); cell.setCellStyle(style); //將輸出寫入文件 try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); } wb.close();
12.填充和顏色
Workbook wb = new XSSFWorkbook(); Sheet sheet = wb.createSheet("new sheet"); //創建一行並在其中放入一些單元格。行從0開始。 Row row = sheet.createRow(1); //水色背景 CellStyle style = wb.createCellStyle(); style.setFillBackgroundColor(IndexedColors.AQUA.getIndex()); style.setFillPattern(FillPatternType.BIG_SPOTS); Cell cell = row.createCell(1); cell.setCellValue("X"); cell.setCellStyle(style); //橙色的“ foreground”,前景是填充前景,而不是字體顏色。 style = wb.createCellStyle(); style.setFillForegroundColor(IndexedColors.ORANGE.getIndex()); style.setFillPattern(FillPatternType.SOLID_FOREGROUND); cell = row.createCell(2); cell.setCellValue("X"); cell.setCellStyle(style); //將輸出寫入文件 try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); } wb.close();
13.合並細胞
Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet("new sheet"); Row row = sheet.createRow(1); Cell cell = row.createCell(1); cell.setCellValue("This is a test of merging"); sheet.addMergedRegion(new CellRangeAddress( 1,//第一行(從0開始) 1,//最后一行(從0開始) 1,//第一列(從0開始) 2 //最后一列(從0開始) )); // Write the output to a file try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); } wb.close();
14.使用字體
Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet("new sheet"); //創建一行並在其中放入一些單元格。行從0開始。 Row row = sheet.createRow(1); //創建一個新字體並進行更改。 Font font = wb.createFont(); font.setFontHeightInPoints((short)24); font.setFontName("Courier New"); font.setItalic(true); font.setStrikeout(true); //字體設置為一種樣式,因此請創建一種新樣式來使用。 CellStyle style = wb.createCellStyle(); style.setFont(font); //創建一個單元格並在其中放置一個值。 Cell cell = row.createCell(1); cell.setCellValue("This is a test of fonts"); cell.setCellStyle(style); //將輸出寫入文件 try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); } wb.close();
請注意,工作簿中唯一字體的最大數量限制為32767。您應該在應用程序中重新使用字體,而不是為每個單元格創建字體。例子:
錯誤
for (int i = 0; i < 10000; i++) { Row row = sheet.createRow(i); Cell cell = row.createCell(0); CellStyle style = workbook.createCellStyle(); Font font = workbook.createFont(); font.setBoldweight(Font.BOLDWEIGHT_BOLD); style.setFont(font); cell.setCellStyle(style); }
正確
CellStyle style = workbook.createCellStyle(); Font font = workbook.createFont(); font.setBoldweight(Font.BOLDWEIGHT_BOLD); style.setFont(font); for (int i = 0; i < 10000; i++) { Row row = sheet.createRow(i); Cell cell = row.createCell(0); cell.setCellStyle(style); }
15.自定義顏色
HHFS:
HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet(); HSSFRow row = sheet.createRow(0); HSSFCell cell = row.createCell(0); cell.setCellValue("Default Palette"); //應用標准調色板中的某些顏色, //如前面的示例。 //我們將在石灰背景上使用紅色文本 HSSFCellStyle style = wb.createCellStyle(); style.setFillForegroundColor(HSSFColor.LIME.index); style.setFillPattern(FillPatternType.SOLID_FOREGROUND); HSSFFont font = wb.createFont(); font.setColor(HSSFColor.RED.index); style.setFont(font); cell.setCellStyle(style); //使用默認調色板保存 try (OutputStream out = new FileOutputStream("default_palette.xls")) { wb.write(out); } //現在,讓我們替換調色板中的RED和LIME //具有更有吸引力的組合 cell.setCellValue("Modified Palette"); //為工作簿創建自定義調色板 HSSFPalette palette = wb.getCustomPalette(); palette.setColorAtIndex(HSSFColor.RED.index, (字節)153,// RGB紅色(0-255) (字節)0,// RGB綠色 (字節)0 // RGB藍色 ); //replacing lime with freebsd.org gold palette.setColorAtIndex(HSSFColor.LIME.index, (byte) 255, (byte) 204, (byte) 102); //保存修改后的調色板 //請注意,無論我們以前使用RED還是LIME的地方, //新顏色神奇地出現 try (out = new FileOutputStream("modified_palette.xls")) { wb.write(out); }
XXSF:
XSSFWorkbook wb = new XSSFWorkbook(); XSSFSheet sheet = wb.createSheet(); XSSFRow row = sheet.createRow(0); XSSFCell cell = row.createCell( 0); cell.setCellValue("custom XSSF colors"); XSSFCellStyle style1 = wb.createCellStyle(); style1.setFillForegroundColor(new XSSFColor(new java.awt.Color(128, 0, 128), new DefaultIndexedColorMap())); style1.setFillPattern(FillPatternType.SOLID_FOREGROUND);
16.讀寫
try (InputStream inp = new FileInputStream("workbook.xls")) { //InputStream inp = new FileInputStream("workbook.xlsx"); Workbook wb = WorkbookFactory.create(inp); Sheet sheet = wb.getSheetAt(0); Row row = sheet.getRow(2); Cell cell = row.getCell(3); if (cell == null) cell = row.createCell(3); cell.setCellType(CellType.STRING); cell.setCellValue("a test"); // Write the output to a file try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); } }
17.在單元格中使用換行符
Workbook wb = new XSSFWorkbook(); //or new HSSFWorkbook(); Sheet sheet = wb.createSheet(); Row row = sheet.createRow(2); Cell cell = row.createCell(2); cell.setCellValue("Use \n with word wrap on to create a new line"); //要啟用換行符,您需要使用wrap = true設置單元格樣式 CellStyle cs = wb.createCellStyle(); cs.setWrapText(true); cell.setCellStyle(cs); //增加行高以容納兩行文本 row.setHeightInPoints((2*sheet.getDefaultRowHeightInPoints())); //調整列寬以適合內容 sheet.autoSizeColumn(2); try (OutputStream fileOut = new FileOutputStream("ooxml-newlines.xlsx")) { wb.write(fileOut); } wb.close();
18.創建用戶定義的數據格式
Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet("format sheet"); CellStyle style; DataFormat format = wb.createDataFormat(); Row row; Cell cell; int rowNum = 0; int colNum = 0; row = sheet.createRow(rowNum++); cell = row.createCell(colNum); cell.setCellValue(11111.25); style = wb.createCellStyle(); style.setDataFormat(format.getFormat("0.0")); cell.setCellStyle(style); row = sheet.createRow(rowNum++); cell = row.createCell(colNum); cell.setCellValue(11111.25); style = wb.createCellStyle(); style.setDataFormat(format.getFormat("#,##0.0000")); cell.setCellStyle(style); try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); } wb.close();
19.將工作表調整為一頁
Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet("format sheet"); PrintSetup ps = sheet.getPrintSetup(); sheet.setAutobreaks(true); ps.setFitHeight((short)1); ps.setFitWidth((short)1); //為電子表格創建各種單元格和行。 try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); } wb.close();
20.設置紙張的打印區域
Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet("Sheet1"); //設置第一張紙的打印區域 wb.setPrintArea(0, "$A$1:$C$2"); //Alternatively: wb.setPrintArea( 0,//工作表索引 0,//開始列 1,//結束列 0,//開始行 0 //結束行 ); try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); } wb.close();
22.在工作表的頁腳上設置頁碼
Workbook wb = new HSSFWorkbook(); // or new XSSFWorkbook(); Sheet sheet = wb.createSheet("format sheet"); Footer footer = sheet.getFooter(); footer.setRight( "Page " + HeaderFooter.page() + " of " + HeaderFooter.numPages() ); //為電子表格創建各種單元格和行。 try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); } wb.close();
23.排行
Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet("row sheet"); //為電子表格創建各種單元格和行。 //將電子表格上的6-11行移至頂部(第0-5行) sheet.shiftRows(5, 10, -5);
24.將工作表設置為選中狀態
Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet("row sheet"); sheet.setSelected(true);
25.設置圖紙的縮放倍率
縮放表示為分數。例如,要表示75%的縮放比例,請將3用作分子,將4用作分母。
Workbook wb = new HSSFWorkbook(); Sheet sheet1 = wb.createSheet("new sheet"); sheet1.setZoom(75); // 放大75%
26.創建拆分和凍結窗格
您可以創建兩種類型的窗格:凍結窗格和拆分窗格。
凍結窗格按列和行划分。使用以下機制創建凍結窗格:
sheet1.createFreezePane(3,2,3,2);
前兩個參數是您希望分割的列和行。后兩個參數指示在右下象限中可見的單元格。
拆分窗格的顯示方式有所不同。分割區域分為四個獨立的工作區域。分割發生在像素級別,用戶可以通過將其拖動到新位置來調整分割。
通過以下調用創建拆分窗格:
sheet2.createSplitPane(2000,2000,0,0,Sheet.PANE_LOWER_LEFT);
第一個參數是拆分的x位置。這是一個點的1/20。在這種情況下,一點似乎等於一個像素。第二個參數是分割的y位置。再次在1/20分之內。
最后一個參數指示當前具有焦點的窗格。這將是Sheet.PANE_LOWER_LEFT,PANE_LOWER_RIGHT,PANE_UPPER_RIGHT或PANE_UPPER_LEFT之一。
Workbook wb = new HSSFWorkbook(); Sheet sheet1 = wb.createSheet("new sheet"); Sheet sheet2 = wb.createSheet("second sheet"); Sheet sheet3 = wb.createSheet("third sheet"); Sheet sheet4 = wb.createSheet("fourth sheet"); //只凍結一行 sheet1.createFreezePane( 0, 1, 0, 1 ); //只凍結一列 sheet2.createFreezePane( 1, 0, 1, 0 ); //凍結列和行(忘記右下象限的滾動位置) sheet3.createFreezePane( 2, 2 ); //創建一個拆分,其左下側為活動象限 sheet4.createSplitPane( 2000, 2000, 0, 0, Sheet.PANE_LOWER_LEFT ); try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); }
27.重復行和列
通過使用Sheet類中的setRepeatingRows()和setRepeatingColumns()方法,可以在打印輸出中設置重復的行和列。
這些方法需要一個CellRangeAddress參數,該參數指定要重復的行或列的范圍。對於setRepeatingRows(),它應指定要重復的行范圍,其中列部分跨越所有列。對於setRepeatingColums(),應指定要重復的列范圍,其中行部分跨越所有行。如果參數為null,則將刪除重復的行或列。
Workbook wb = new HSSFWorkbook(); // or new XSSFWorkbook(); Sheet sheet1 = wb.createSheet("Sheet1"); Sheet sheet2 = wb.createSheet("Sheet2"); //設置要在第一張紙上的第4到5列重復的行。 sheet1.setRepeatingRows(CellRangeAddress.valueOf("4:5")); //將列設置為在第二張紙上從A列重復到C列 sheet2.setRepeatingColumns(CellRangeAddress.valueOf("A:C")); try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); }
28.頁眉和頁腳
示例適用於頁眉,但直接應用於頁腳。
Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet("new sheet"); Header header = sheet.getHeader(); header.setCenter("Center Header"); header.setLeft("Left Header"); header.setRight(HSSFHeader.font("Stencil-Normal", "Italic") + HSSFHeader.fontSize((short) 16) + "Right w/ Stencil-Normal Italic font and size 16"); try (OutputStream fileOut = new FileOutputStream("workbook.xls")) { wb.write(fileOut); }
29.XSSF對頁眉和頁腳的增強
示例適用於頁眉,但直接應用於頁腳。請注意,上面的基本頁眉和頁腳示例適用於XSSF工作簿以及HSSF工作簿。HSSFHeader內容不適用於XSSF工作簿。
XSSF能夠處理首頁頁眉和頁腳以及偶數/奇數頁眉和頁腳。所有標頭/頁腳屬性標志也可以在XSSF中處理。奇數頁眉和頁腳是默認的頁眉和頁腳。它顯示在所有不顯示首頁標題或偶數頁標題的頁面上。也就是說,如果偶數頁眉/頁腳不存在,則奇數頁眉/頁腳將顯示在偶數頁上。如果第一頁的頁眉/頁腳不存在,則奇數頁眉/頁腳將顯示在第一頁上。如果未設置even / odd屬性,則與不存在偶數頁眉/頁腳相同。
Workbook wb = new XSSFWorkbook(); XSSFSheet sheet = (XSSFSheet) wb.createSheet("new sheet"); //創建首頁標題 Header header = sheet.getFirstHeader(); header.setCenter("Center First Page Header"); header.setLeft("Left First Page Header"); header.setRight("Right First Page Header"); //創建一個偶數頁眉 Header header2 = sheet.getEvenHeader(); der2.setCenter("Center Even Page Header"); header2.setLeft("Left Even Page Header"); header2.setRight("Right Even Page Header"); //創建一個奇數頁頭 Header header3 = sheet.getOddHeader(); der3.setCenter("Center Odd Page Header"); header3.setLeft("Left Odd Page Header"); header3.setRight("Right Odd Page Header"); //設置/刪除標題屬性 XSSFHeaderProperties prop = sheet.getHeaderFooterProperties(); prop.setAlignWithMargins(); prop.scaleWithDoc(); prop.removeDifferentFirstPage(); //這不會刪除首頁的頁眉或頁腳 prop.removeDifferentEvenOdd(); //這不會刪除頁眉或頁腳 try (OutputStream fileOut = new FileOutputStream("workbook.xlsx")) { wb.write(fileOut); }
30.繪圖形狀
POI支持使用Microsoft Office繪圖工具繪制圖形。圖紙上的形狀按組和形狀的層次結構進行組織。最高的形狀是族長。這一點在工作表上根本看不到。要開始繪制,您需要 在HSSFSheet類上調用createPatriarch。這具有擦除存儲在該紙張中的任何其他形狀信息的效果。默認情況下,除非您調用此方法,否則POI會將形狀記錄留在工作表中。
要創建形狀,您必須執行以下步驟:
- 創建族長。
- 創建錨點以將形狀放置在圖紙上。
- 要求族長創造形狀。
- 設置形狀類型(線,橢圓,矩形等)
- 設置有關形狀的其他樣式詳細信息。(例如:線寬等)
HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 1, 0, (short) 1, 0 ); HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1); shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
使用不同的調用創建文本框:
HSSFTextbox textbox1 = patriarch.createTextbox( new HSSFClientAnchor(0,0,0,0,(short)1,1,(short)2,2)); textbox1.setString(new HSSFRichTextString("This is a test") );
可以使用不同的字體來設置文本框中文本的樣式。這是如何做:
HSSFFont font = wb.createFont(); font.setItalic(true); font.setUnderline(HSSFFont.U_DOUBLE); HSSFRichTextString string = new HSSFRichTextString("Woo!!!"); string.applyFont(2,5,font); textbox.setString(string );
就像可以使用Excel手動完成一樣,可以將形狀分組在一起。這是通過調用 createGroup()然后使用這些組創建形狀來完成的。
也可以在組內創建組。
以下是創建形狀組的方法:
//創建形狀組。 HSSFShapeGroup group = patriarch.createGroup( new HSSFClientAnchor(0,0,900,200,(short)2,2,(short)2,2)); //在組中創建幾行。 HSSFSimpleShape shape1 = group.createShape(new HSSFChildAnchor(3,3,500,500)); shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE); ( (HSSFChildAnchor) shape1.getAnchor() ).setAnchor(3,3,500,500); HSSFSimpleShape shape2 = group.createShape(new HSSFChildAnchor(1,200,400,600)); shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
如果您觀察的話,會發現添加到組中的形狀使用了一種新型的錨點:HSSFChildAnchor。發生的情況是,所創建的組具有自己的坐標空間,用於放置到其中的形狀。POI將此默認設置為(0,0,1023,255),但是您可以根據需要進行更改。這是如何做:
myGroup.setCoordinates(10,10,20,20); //左上,右下
如果您在一個組內創建一個組,則還將擁有它自己的坐標空間。
31.造型形狀
默認情況下,形狀看起來有點普通。但是,可以對形狀應用不同的樣式。目前可以完成的事情有:
- 更改填充顏色。
- 制作沒有填充顏色的形狀。
- 更改線條的粗細。
- 更改線條的樣式。例如:虛線,虛線。
- 更改線條顏色。
這是完成此操作的示例:
HSSFSimpleShape s = patriarch.createSimpleShape(a); s.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL); s.setLineStyleColor(10,10,10); s.setFillColor(90,10,200); s.setLineWidth(HSSFShape.LINEWIDTH_ONE_PT * 3); s.setLineStyle(HSSFShape.LINESTYLE_DOTSYS);
32.形狀和圖形
雖然推薦使用本機POI形狀繪制命令來繪制形狀,但有時還是希望使用標准API與外部庫兼容。考慮到這一點,我們為Graphics和Graphics2d創建了一些包裝。
所有圖形命令均發布到HSSFShapeGroup中。這是完成的過程:
a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 1, 0, (short) 1, 0 ); group = patriarch.createGroup( a ); group.setCoordinates( 0, 0, 80 * 4 , 12 * 23 ); float verticalPointsPerPixel = a.getAnchorHeightInPoints(sheet) / (float)Math.abs(group.getY2() - group.getY1()); g = new EscherGraphics( group, wb, Color.black, verticalPointsPerPixel ); g2d = new EscherGraphics2d( g ); drawChemicalStructure( g2d );
我們要做的第一件事是創建組並設置其坐標以匹配我們計划繪制的對象。接下來,我們計算一個合理的fontSizeMultiplier,然后創建EscherGraphics對象。由於我們真正想要的是Graphics2d 對象,因此我們創建了EscherGraphics2d對象並傳入我們創建的圖形對象。最后,我們調用一個提取EscherGraphics2d對象的例程。
每個像素的垂直點值得更多解釋。將Graphics調用轉換為escher繪圖調用的困難之一是Excel沒有絕對像素位置的概念。它以“字符”為單位測量單元格寬度,以點為單位測量單元格高度。不幸的是,它並沒有確切定義要測量的字符類型。大概這是由於Excel將在不同平台上甚至在同一平台上使用不同字體的事實。
由於這種限制,我們不得不實現verticalPointsPerPixel的概念。發出諸如drawString()之類的命令時,字體應縮放的數量。要計算此值,請使用以下公式:
multipler = groupHeightInPoints / heightOfGroup
通過計算形狀的邊界框的y坐標之間的差,可以非常簡單地計算出組的高度。可以使用稱為HSSFClientAnchor.getAnchorHeightInPoints()的便捷性來計算組的高度 。
圖形類支持的許多功能都不完整。這是一些已知可以正常工作的功能。
- fillRect()
- fillOval()
- drawString()
- drawOval()
- drawLine()
- clearRect()
不支持的功能將使用POI日志記錄基礎結構(默認情況下禁用)返回並記錄消息。
33.概述
大綱非常適合將信息的各個部分組合在一起,並且可以使用POI API輕松地將其添加到列和行中。這是如何做:
Workbook wb = new HSSFWorkbook(); Sheet sheet1 = wb.createSheet("new sheet"); sheet1.groupRow( 5, 14 ); sheet1.groupRow( 7, 14 ); sheet1.groupRow( 16, 19 ); sheet1.groupColumn( 4, 7 ); sheet1.groupColumn( 9, 12 ); sheet1.groupColumn( 10, 11 ); try (OutputStream fileOut = new FileOutputStream(filename)) { wb.write(fileOut); }
要折疊(或展開)輪廓,請使用以下調用:
sheet1.setRowGroupCollapsed(7,true); sheet1.setColumnGroupCollapsed(4,true)
您選擇的行/列應包含一個已創建的組。它可以在組中的任何位置。
34.圖片
圖像是圖形支持的一部分。要添加圖像,只需在繪圖族長上調用createPicture()。在撰寫本文時,支持以下類型:
- PNG
- JPG格式
- DIB
應當注意,一旦將圖像添加到圖紙上,任何現有的圖紙都可能被刪除
//創建一個新的工作簿 Workbook wb = new XSSFWorkbook(); //or new HSSFWorkbook(); //將圖片數據添加到此工作簿。 InputStream is = new FileInputStream("image1.jpeg"); byte[] bytes = IOUtils.toByteArray(is); int pictureIdx = wb.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG); is.close(); CreationHelper helper = wb.getCreationHelper(); //創建工作表 Sheet sheet = wb.createSheet(); //創建繪圖族長。這是所有形狀的頂層容器。 Drawing drawing = sheet.createDrawingPatriarch(); //添加圖片形狀 ClientAnchor anchor = helper.createClientAnchor(); //設置圖片的左上角, //隨后調用Picture#resize()將相對於它進行操作 anchor.setCol1(3); anchor.setRow1(2); Picture pict = drawing.createPicture(anchor, pictureIdx); //相對於左上角的圖片自動調整大小 pict.resize(); //保存工作簿 String file = "picture.xls"; if(wb instanceof XSSFWorkbook) file += "x"; try (OutputStream fileOut = new FileOutputStream(file)) { wb.write(fileOut); }
從工作簿中讀取圖像:
ist lst = workbook.getAllPictures(); or (Iterator it = lst.iterator(); it.hasNext(); ) { PictureData pict = (PictureData)it.next(); String ext = pict.suggestFileExtension(); byte[] data = pict.getData(); if (ext.equals("jpeg")){ try (OutputStream out = new FileOutputStream("pict.jpg")) { out.write(data); } }
35.命名范圍和命名單元格
命名范圍是一種通過名稱引用一組單元格的方法。命名單元格是命名范圍的簡寫情況,因為“單元格組”恰好包含一個單元格。您可以在工作簿中按其命名范圍創建和引用單元格。使用命名范圍時,將使用org.apache.poi.ss.util.CellReference 和org.apache.poi.ss.util.AreaReference類。
注意:使用諸如'A1:B1'之類的相對值會導致在Microsoft Excel中使用該工作簿時該名稱指向的單元格的意外移動,通常使用諸如'$ A $ 1:$ B $ 1'之類的絕對引用可以避免這種情況,另請參閱 此討論。
創建命名范圍/命名單元格
//設置代碼 String sname = "TestSheet", cname = "TestName", cvalue = "TestVal"; Workbook wb = new HSSFWorkbook(); Sheet sheet = wb.createSheet(sname); sheet.createRow(0).createCell(0).setCellValue(cvalue); // 1.使用areareference為單個單元格創建命名范圍 Name namedCell = wb.createName(); namedCell.setNameName(cname + "1"); String reference = sname+"!$A$1:$A$1"; // area reference namedCell.setRefersToFormula(reference); // 2.使用cellreference為單個單元格創建命名范圍 Name namedCel2 = wb.createName(); namedCel2.setNameName(cname + "2"); reference = sname+"!$A$1"; // cell reference namedCel2.setRefersToFormula(reference); // 3.使用AreaReference為區域創建命名范圍 Name namedCel3 = wb.createName(); namedCel3.setNameName(cname + "3"); reference = sname+"!$A$1:$C$5"; // area reference namedCel3.setRefersToFormula(reference); // 4.創建命名公式 Name namedCel4 = wb.createName(); namedCel4.setNameName("my_sum"); namedCel4.setRefersToFormula("SUM(" + sname + "!$I$2:$I$6)");
從命名范圍/命名單元格讀取
//設置代碼 String cname = "TestName"; Workbook wb = getMyWorkbook(); // retrieve workbook //檢索命名范圍 int namedCellIdx = wb.getNameIndex(cellName); Name aNamedCell = wb.getNameAt(namedCellIdx); //檢索指定范圍內的單元格並測試其內容 AreaReference aref = new AreaReference(aNamedCell.getRefersToFormula()); CellReference[] crefs = aref.getAllReferencedCells(); for (int i=0; i<crefs.length; i++) { Sheet s = wb.getSheet(crefs[i].getSheetName()); Row r = sheet.getRow(crefs[i].getRow()); Cell c = r.getCell(crefs[i].getCol()); //根據單元格類型等提取單元格內容 }
從不連續的命名范圍讀取
//設置代碼 String cname = "TestName"; Workbook wb = getMyWorkbook(); // retrieve workbook //檢索命名范圍 //將類似於“ $ C $ 10,$ D $ 12:$ D $ 14”; int namedCellIdx = wb.getNameIndex(cellName); Name aNamedCell = wb.getNameAt(namedCellIdx); //檢索指定范圍內的單元格並測試其內容 //將獲取C10的一個AreaReference,然后 // D12到D14的另一個 AreaReference[] arefs = AreaReference.generateContiguous(aNamedCell.getRefersToFormula()); for (int i=0; i<arefs.length; i++) { //只獲取區域的角落 //(使用arefs [i] .getAllReferencedCells()獲取所有單元格) CellReference[] crefs = arefs[i].getCells(); for (int j=0; j<crefs.length; j++) { // Check it turns into real stuff Sheet s = wb.getSheet(crefs[j].getSheetName()); Row r = s.getRow(crefs[j].getRow()); Cell c = r.getCell(crefs[j].getCol()); //對這個角落單元格進行操作 } }
請注意,刪除單元格后,Excel不會刪除附加的命名范圍。因此,工作簿可以包含指向不再存在的單元格的命名范圍。在構造AreaReference之前,您應該檢查參考的有效性。
if(name.isDeleted()){ //已命名的范圍指向已刪除的單元格。 } else { AreaReference ref = new AreaReference(name.getRefersToFormula()); }
36.如何設置單元格注釋
注釋是附於單元格並與單元格關聯的富文本注釋,與其他單元格內容分開。注釋內容與單元格分開存儲,並顯示在與單元格獨立但相關聯的圖形對象(如文本框)中
Workbook wb = new XSSFWorkbook(); //or new HSSFWorkbook(); CreationHelper factory = wb.getCreationHelper(); Sheet sheet = wb.createSheet(); Row row = sheet.createRow(3); Cell cell = row.createCell(5); cell.setCellValue("F4"); Drawing drawing = sheet.createDrawingPatriarch(); //當注釋框可見時,將其顯示在1x3的空間中 ClientAnchor anchor = factory.createClientAnchor(); anchor.setCol1(cell.getColumnIndex()); anchor.setCol2(cell.getColumnIndex()+1); anchor.setRow1(row.getRowNum()); anchor.setRow2(row.getRowNum()+3); //創建評論並設置文字+作者 Comment comment = drawing.createCellComment(anchor); RichTextString str = factory.createRichTextString("Hello, World!"); comment.setString(str); comment.setAuthor("Apache POI"); //將注釋分配給單元格 cell.setCellComment(comment); String fname = "comment-xssf.xls"; if(wb instanceof XSSFWorkbook) fname += "x"; try (OutputStream out = new FileOutputStream(fname)) { wb.write(out); } wb.close();
閱讀單元格注釋
Cell cell = sheet.get(3).getColumn(1); Comment comment = cell.getCellComment(); if (comment != null) { RichTextString str = comment.getString(); String author = comment.getAuthor(); } //或者,您也可以按(行,列)檢索單元格注釋 comment = sheet.getCellComment(3, 1);
要獲得工作表上的所有評論:
Map<CellAddress, Comment> comments = sheet.getCellComments(); Comment commentA1 = comments.get(new CellAddress(0, 0)); Comment commentB1 = comments.get(new CellAddress(0, 1)); for (Entry<CellAddress, ? extends Comment> e : comments.entrySet()) { CellAddress loc = e.getKey(); Comment comment = e.getValue(); System.out.println("Comment at " + loc + ": " + "[" + comment.getAuthor() + "] " + comment.getString().getString()); }
37.如何調整列寬以適合內容
Sheet sheet = workbook.getSheetAt(0); sheet.autoSizeColumn(0); //調整第一列的寬度 sheet.autoSizeColumn(1); //調整第二列的寬度
僅對於SXSSFWorkbooks,因為隨機訪問窗口可能會排除工作表中的大多數行,而這是計算列的最佳匹配寬度所必需的,因此在刷新任何行之前,必須跟蹤這些列以自動調整大小。
SXSSFWorkbook workbook = new SXSSFWorkbook(); SXSSFSheet sheet = workbook.createSheet(); sheet.trackColumnForAutoSizing(0); sheet.trackColumnForAutoSizing(1); //如果您具有列索引的Collection,請參見SXSSFSheet#trackColumnForAutoSizing(Collection <Integer>) //或滾動自己的for循環。 //或者,如果沒有自動調整大小的列,請使用SXSSFSheet#trackAllColumnsForAutoSizing() //預先知道,或者您正在升級現有代碼,並試圖最小化更改。記住 //由於計算出最適合的寬度,因此跟蹤所有列將需要更多的內存和CPU周期 //在刷新的每一行的所有跟蹤列上。 //創建一些單元格 for (int r=0; r < 10; r++) { Row row = sheet.createRow(r); for (int c; c < 10; c++) { Cell cell = row.createCell(c); cell.setCellValue("Cell " + c.getAddress().formatAsString()); } } //自動調整列的大小。 sheet.autoSizeColumn(0); sheet.autoSizeColumn(1);
請注意,Sheet#autoSizeColumn()不計算公式單元格,公式單元格的寬度是根據緩存的公式結果計算的。如果您的工作簿有很多公式,那么在自動調整大小之前最好對它們進行評估。
38.超連結
如何閱讀超鏈接
Sheet sheet = workbook.getSheetAt(0); Cell cell = sheet.getRow(0).getCell(0); Hyperlink link = cell.getHyperlink(); if(link != null){ System.out.println(link.getAddress()); }
如何創建超鏈接
Workbook wb = new XSSFWorkbook(); //or new HSSFWorkbook(); CreationHelper createHelper = wb.getCreationHelper(); //超鏈接的單元格樣式 //默認情況下,超鏈接為藍色並帶有下划線 CellStyle hlink_style = wb.createCellStyle(); Font hlink_font = wb.createFont(); hlink_font.setUnderline(Font.U_SINGLE); hlink_font.setColor(IndexedColors.BLUE.getIndex()); hlink_style.setFont(hlink_font); Cell cell; Sheet sheet = wb.createSheet("Hyperlinks"); //URL cell = sheet.createRow(0).createCell(0); cell.setCellValue("URL Link"); Hyperlink link = createHelper.createHyperlink(Hyperlink.LINK_URL); link.setAddress("https://poi.apache.org/"); cell.setHyperlink(link); cell.setCellStyle(hlink_style); //鏈接到當前目錄中的文件 cell = sheet.createRow(1).createCell(0); cell.setCellValue("File Link"); link = createHelper.createHyperlink(Hyperlink.LINK_FILE); link.setAddress("link1.xls"); cell.setHyperlink(link); cell.setCellStyle(hlink_style); //電子郵件鏈接 cell = sheet.createRow(2).createCell(0); cell.setCellValue("Email Link"); link = createHelper.createHyperlink(Hyperlink.LINK_EMAIL); ///注意,如果主題中包含空格,請確保其為url編碼 link.setAddress("mailto:poi@apache.org?subject=Hyperlinks"); cell.setHyperlink(link); cell.setCellStyle(hlink_style); //鏈接到此工作簿中的位置 //創建目標工作表和單元格 Sheet sheet2 = wb.createSheet("Target Sheet"); sheet2.createRow(0).createCell(0).setCellValue("Target Cell"); cell = sheet.createRow(3).createCell(0); cell.setCellValue("Worksheet Link"); Hyperlink link2 = createHelper.createHyperlink(Hyperlink.LINK_DOCUMENT); link2.setAddress("'Target Sheet'!A1"); cell.setHyperlink(link2); cell.setCellStyle(hlink_style); try (OutputStream out = new FileOutputStream("hyperinks.xlsx")) { wb.write(out); } wb.close();
39.資料驗證
40.嵌入式對象
41.自動過濾器
42.條件格式
43.隱藏和取消隱藏行
44.設置單元格屬性
45.繪制邊框
46.創建數據透視表
47.具有多種樣式的單元格
