apache-poi之Excel使用API

目录

概述

基本用法

 

新工作簿 New Workbook

新表 New Sheet

创建单元格 Creating Cells

创建日期单元格 Creating Date Cells

使用不同类型的单元格 Working with different types of cells

文件与输入流 Files vs InputStreams

演示各种对齐选项

边框设置 Working with borders

迭代行和单元格 Iterate over rows and cells

迭代单元格,控制丢失的/空白单元格 Iterate over cells, with control of missing / blank cells

获取单元格内容 Getting the cell contents

文本提取 Text Extraction

填充和颜色 Fills and colors

合并单元格 Merging cells

使用字体 Working with fonts

自定义颜色

阅读和重写工作簿 Reading and Rewriting Workbooks

在单元格中使用换行符 Using newlines in cells

数据格式 Data Formats

适合一页的工作表 Fit Sheet to One Page

设置打印区域 Set Print Area

在页脚上设置页码 Set Page Numbers on Footer

使用便捷功能 Using the Convenience Functions

在工作表上向上或向下移动行 Shift rows up or down on a sheet

将工作表设置为选中 Set a sheet as selected

设置缩放倍率 Set the zoom magnification

拆分和冻结窗格 Splits and freeze panes

重复行和列 Repeating rows and columns

页眉和页脚 Headers and Footers

XSSF增强页眉和页脚 XSSF Enhancement for Headers and Footers

绘图形状 Drawing Shapes

造型形状 Styling Shapes

形状和图形2d Shapes and Graphics2d

大纲 Outlining

图片 Images

 命名范围和命名单元格

 单元格评论 - HSSF和XSSF 

调整列宽以适合内容

 如何阅读超链接

 如何创建超链接

 数据验证

hssf.usermodel(二进制.xls格式)

 xssf.usermodel(.xlsx格式)

ss.usermodel

嵌入对象

自动筛选

条件格式

隐藏和不隐藏的行

设置单元格属性

绘图边框

创建数据透视表

具有多种样式的单元格(富文本字符串)

新的通用SS Usermodel代码(支持全部excel版本)


概述


      IndexedColors颜色参考: 地址

      POI需要包查看例如:excel maven包为poi和poi-ooxml,新版本和旧版本的包

Component Application type Maven artifactId Notes
POIFS OLE2 Filesystem poi Required to work with OLE2 / POIFS based files
HPSF OLE2 Property Sets poi  
HSSF Excel XLS poi For HSSF only, if common SS is needed see below
HSLF PowerPoint PPT poi-scratchpad  
HWPF Word DOC poi-scratchpad  
HDGF Visio VSD poi-scratchpad  
HPBF Publisher PUB poi-scratchpad  
HSMF Outlook MSG poi-scratchpad  
DDF Escher common drawings poi  
HWMF WMF drawings poi-scratchpad  
OpenXML4J OOXML poi-ooxml plus either poi-ooxml-schemasor
ooxml-schemas and ooxml-security
See notes below for differences between these options
XSSF Excel XLSX poi-ooxml  
XSLF PowerPoint PPTX poi-ooxml  
XWPF Word DOCX poi-ooxml  
XDGF Visio VSDX poi-ooxml  
Common SL PowerPoint PPT and PPTX poi-scratchpad and poi-ooxml SL code is in the core POI jar, but implementations are in poi-scratchpad and poi-ooxml.
Common SS Excel XLS and XLSX poi-ooxml WorkbookFactory and friends all require poi-ooxml, not just core poi

HSSF是POI项目的Excel '97(-2007)文件格式的纯Java实现。XSSF是POI Project的Excel 2007 OOXML(.xlsx)文件格式的纯Java实现。

HSSF和XSSF提供了阅读电子表格创建,修改,读取和写入XLS电子表格的方法。他们提供:

  • 低水平的结构,为有特殊需要的人
  • 一个eventmodel api,用于高效的只读访问
  • 用于创建,读取和修改XLS文件的完整usermodel api

对于希望使用联合SS Usermodel进行HSSF和XSSF支持的纯HSSF用户模型转换的人员,请参阅ss usermodel转换指南。

生成电子表格的另一种方法是通过Cocoon序列化程序(但您仍将间接使用HSSF)。使用Cocoon,您可以通过简单地应用样式表和指定序列化程序来序列化任何XML数据源(例如,可能是在SQL中输出的ESQL页面)。

如果您只是阅读电子表格数据,请在org.apache.poi.hssf.eventusermodel包或org.apache.poi.xssf.eventusermodel包中使用eventmodel api,具体取决于您的文件格式。

如果您要修改电子表格数据,请使用usermodel api。您也可以通过这种方式生成电子表格。

请注意,usermodel系统具有比低级eventusermodel更高的内存占用,但具有使用起来更简单的主要优点。另请注意,由于新的XSSF支持Excel 2007 OOXML(.xlsx)文件是基于XML的,因此处理它们的内存占用量高于旧版HSSF支持的(.xls)二进制文件。

自3.8-beta3以来,POI提供了基于XSSF构建的低内存占用SXSSF API。

SXSSF是XSSF的API兼容流式扩展,用于在必须生成非常大的电子表格时使用,并且堆空间有限。SXSSF通过限制对滑动窗口内行的访问来实现其低内存占用,而XSSF允许访问文档中的所有行。不再在窗口中的旧行变得不可访问,因为它们被写入磁盘。

在自动刷新模式下,可以指定访问窗口的大小,以在内存中保存一定数量的行。达到该值时,创建附加行会导致索引最低的行从访问窗口中删除并写入磁盘。或者,窗口大小可以设置为动态增长; 它可以根据需要通过显式调用flushRows(int keepRows)定期修剪。

由于实现的流式特性,与XSSF相比存在以下限制:

  • 在某个时间点只能访问有限数量的行。
  • 不支持Sheet.clone()。
  • 不支持公式评估

基本用法


 

新工作簿 New Workbook

  Workbook wb = new HSSFWorkbook();
    ...
    try  (OutputStream fileOut = new FileOutputStream("workbook.xls")) {
        wb.write(fileOut);
    }

    Workbook wb = new XSSFWorkbook();
    ...
    try (OutputStream fileOut = new FileOutputStream("workbook.xlsx")) {
        wb.write(fileOut);
    }

 

 

新表 New Sheet

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*?]"); //返回“O'Brien的销售额”
    Sheet sheet3 = wb.createSheet(safeName);

    try (OutputStream fileOut = new FileOutputStream("workbook.xls")) {
        wb.write(fileOut);
    }

创建单元格 Creating Cells

 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);
    }

创建日期单元格 Creating Date Cells

 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);
    }

使用不同类型的单元格 Working with different types of cells

 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);
    }

文件与输入流 Files vs 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"));

如果直接使用HSSFWorkbookXSSFWorkbook,通常应该通过NPOIFSFileSystem或 OPCPackage来完全控制生命周期(包括完成后关闭文件):

  // HSSFWorkbook,文件
  NPOIFSFileSystem fs = new NPOIFSFileSystem(new File("file.xls"));
  HSSFWorkbook wb = new HSSFWorkbook(fs.getRoot(), true);
  ....
  fs.close();

  // HSSFWorkbook,InputStream,需要更多内存
  NPOIFSFileSystem fs = new NPOIFSFileSystem(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();

演示各种对齐选项

 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);

        // Write the output to a file
        try (OutputStream fileOut = new FileOutputStream("xssf-align.xlsx")) {
            wb.write(fileOut);
        }

        wb.close();
    }


 / **
     *创建一个单元格并以某种方式对齐它。
     *
     * @param wb工作簿
     * @param在行中创建单元格
     * @param列用于创建单元格的列号
     * @param halign单元格的水平对齐方式。
     * @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);
    }

边框设置 Working with borders

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();

迭代行和单元格 Iterate over rows and cells

有时,您只想迭代工作簿中的所有工作表,工作表中的所有行或连续的所有单元格。这可以通过简单的for循环实现。通过调用workbook.sheetIterator(), sheet.rowIterator()row.cellIterator(),或隐式使用for-each循环,可以使用这些迭代器。请注意,rowIterator和cellIterator迭代已创建的行或单元格,跳过空行和单元格。

for (Sheet sheet : wb ) {
        for (Row row : sheet) {
            for (Cell cell : row) {
                // 操作
            }
        }
    }

迭代单元格,控制丢失的/空白单元格 Iterate over cells, with control of missing / blank cells

在某些情况下,在迭代时,您需要完全控制缺失或空白行和单元格的处理方式,并且您需要确保访问每个单元格而不仅仅是文件中定义的单元格。(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 {
             //对单元格的内容做一些有用的事情
          }
       }
    }

获取单元格内容 Getting the cell contents

要获取单元格的内容,首先需要知道它是什么类型的单元格(例如,询问字符串单元格的数字内容会获得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(" - ");

           //通过获取单元格值并应用任何数据格式(Date,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();
            }
        }
    }

文本提取 Text Extraction

对于大多数文本提取要求,标准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();
    }

 

填充和颜色 Fills and colors

 Workbook wb = new XSSFWorkbook();
    Sheet sheet = wb.createSheet("new sheet");

   //创建一行并在其中放入一些单元格。行以0为基础。
    Row row = sheet.createRow(1);
 
    // Aqua背景
    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);

   //橙色“前景”,前景是填充前景而不是字体颜色。
    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();

合并单元格 Merging cells

 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开始)
    ));

   //将输出写入文件
    try (OutputStream fileOut = new FileOutputStream("workbook.xls")) {
        wb.write(fileOut);
    }

    wb.close();

使用字体 Working with fonts

 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);
    }

自定义颜色

HSSF:

 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
    //更具吸引力的组合
    //(亲自从freebsd.org借来的)

    cell.setCellValue("Modified Palette");

    //为工作簿创建自定义调色板
    HSSFPalette palette = wb.getCustomPalette();

    //replacing the standard red with freebsd.org red
    palette.setColorAtIndex(HSSFColor.RED.index,
            (byte) 153,  //RGB red (0-255)
            (byte) 0,    //RGB green
            (byte) 0     //RGB blue
    );
    //用freebsd.org red替换标准红色
    palette.setColorAtIndex(HSSFColor.LIME.index, (byte) 255, (byte) 204, (byte) 102);

    //使用修改后的调色板保存
    //请注意,无论我们以前在哪里使用RED或LIME,都可以
    //神奇地出现了新的颜色
    try (out = new FileOutputStream("modified_palette.xls")) {
        wb.write(out);
    }

XSSF:

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);

阅读和重写工作簿 Reading and Rewriting Workbooks

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");
    
        //将输出写入文件
        try (OutputStream fileOut = new FileOutputStream("workbook.xls")) {
            wb.write(fileOut);
        }
    }

在单元格中使用换行符 Using newlines in cells

 Workbook wb = new XSSFWorkbook();   //or new HSSFWorkbook();
    Sheet sheet = wb.createSheet();

    Row row = sheet.createRow(2);
    Cell cell = row.createCell(2);
    cell.setCellValue("使用\ n,自动换行以创建新行");

    //要启用您需要的换行符,请使用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();

数据格式 Data Formats

 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();
                    

适合一页的工作表 Fit Sheet to One Page

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();
                    

设置打印区域 Set Print Area

 Workbook wb = new HSSFWorkbook();
    Sheet sheet = wb.createSheet("Sheet1");
    //设置第一张纸的打印区域
    wb.setPrintArea(0, "$A$1:$C$2");
    
    //或者:
    wb.setPrintArea(
            0,//工作表索引
            0,//开始列
            1,//结束列
            0,//开始行
            0 //结束行

    try (OutputStream fileOut = new FileOutputStream("workbook.xls")) {
        wb.write(fileOut);
    }

    wb.close();

在页脚上设置页码 Set Page Numbers on Footer

 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();

使用便捷功能 Using the Convenience Functions

便捷功能提供实用功能,例如在合并区域周围设置边框和更改样式属性,而无需显式创建新样式。

 Workbook wb = new HSSFWorkbook();  // or new XSSFWorkbook()
    Sheet sheet1 = wb.createSheet( "new sheet" );

    //创建合并区域
    Row row = sheet1.createRow( 1 );
    Row row2 = sheet1.createRow( 2 );
    Cell cell = row.createCell( 1 );
    cell.setCellValue( "This is a test of merging" );
    CellRangeAddress region = CellRangeAddress.valueOf("B2:E5");
    sheet1.addMergedRegion( region );

    //设置边框和边框颜色。
    RegionUtil.setBorderBottom( BorderStyle.MEDIUM_DASHED, region, sheet1, wb );
    RegionUtil.setBorderTop(    BorderStyle.MEDIUM_DASHED, region, sheet1, wb );
    RegionUtil.setBorderLeft(   BorderStyle.MEDIUM_DASHED, region, sheet1, wb );
    RegionUtil.setBorderRight(  BorderStyle.MEDIUM_DASHED, region, sheet1, wb );
    RegionUtil.setBottomBorderColor(IndexedColors.AQUA.getIndex(), region, sheet1, wb);
    RegionUtil.setTopBorderColor(   IndexedColors.AQUA.getIndex(), region, sheet1, wb);
    RegionUtil.setLeftBorderColor(  IndexedColors.AQUA.getIndex(), region, sheet1, wb);
    RegionUtil.setRightBorderColor( IndexedColors.AQUA.getIndex(), region, sheet1, wb);

    ///显示HSSFCellUtil的一些用法
    CellStyle style = wb.createCellStyle();
    style.setIndention((short)4);
    CellUtil.createCell(row, 8, "这是单元格的值", style);
    Cell cell2 = CellUtil.createCell( row2, 8, "这是单元格的值");
    CellUtil.setAlignment(cell2, HorizontalAlignment.CENTER);

    //写出工作簿
    try (OutputStream fileOut = new FileOutputStream( "workbook.xls" )) {
        wb.write( fileOut );
    }

    wb.close();

在工作表上向上或向下移动行 Shift rows up or down on a sheet

 Workbook wb = new HSSFWorkbook();
        Sheet sheet = wb.createSheet("row sheet");

        //为电子表格创建各种单元格和行。

        //将电子表格中的第6  -  11行移到顶部(第0  -  5行)
        sheet.shiftRows(5, 10, -5);

将工作表设置为选中 Set a sheet as selected

 Workbook wb = new HSSFWorkbook();
    Sheet sheet = wb.createSheet("row sheet");
    sheet.setSelected(true);

设置缩放倍率 Set the zoom magnification

缩放表示为分数。例如,为了表示75%的缩放,使用3作为分子,使用4作为分母。

 Workbook wb = new HSSFWorkbook();
    Sheet sheet1 = wb.createSheet("new sheet");
    sheet1.setZoom(75);   // 75%的放大率

拆分和冻结窗格 Splits and freeze panes

您可以创建两种类型的窗格; 冻结窗格和拆分窗格。

冻结窗格按列和行分割。您可以使用以下机制创建冻结窗格:

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);
    }

重复行和列 Repeating rows and columns

通过使用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);
    }

页眉和页脚 Headers and Footers

示例适用于标题,但直接应用于页脚。

 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);
    }

XSSF增强页眉和页脚 XSSF Enhancement for Headers and Footers

示例适用于标题,但直接应用于页脚。请注意,上面的基本页眉和页脚示例适用于XSSF工作簿以及HSSF工作簿。HSSFHeader内容不适用于XSSF工作簿。

XSSF能够处理第一页页眉和页脚,以及偶数/奇数页眉和页脚。所有页眉/页脚属性标志也可以在XSSF中处理。奇数页眉和页脚是默认的页眉和页脚。它显示在所有不显示第一页标题或偶数页标题的页面上。也就是说,如果Even页眉/页脚不存在,则在偶数页面上显示奇数页眉/页脚。如果第一页页眉/页脚不存在,则在第一页上显示奇数页眉/页脚。如果未设置偶数/奇数属性,则与不存在的偶数页眉/页脚相同。

 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();
	header2.setCenter("Center Even Page Header");
    header2.setLeft("Left Even Page Header");
    header2.setRight("Right Even Page Header");
    
    //创建一个奇数页面标题
    Header header3 = sheet.getOddHeader();
	header3.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(); //这不会删除第一页页眉或页脚footers
    prop.removeDifferentEvenOdd(); //这不会删除页眉或页脚
    
    try (OutputStream fileOut = new FileOutputStream("workbook.xlsx")) {
        wb.write(fileOut);
    }

绘图形状 Drawing Shapes

POI支持使用Microsoft Office绘图工具绘制形状。工作表上的形状按组和形状的层次结构组织。最顶级的形状是族长。这在纸张上根本看不到。要开始绘图,您需要 在HSSFSheet类上调用createPatriarch。这具有擦除存储在该表中的任何其他形状信息的效果。默认情况下,除非您调用此方法,否则POI将在工作表中单独保留形状记录。

要创建形状,您必须执行以下步骤:

  1. 创造族长。
  2. 创建锚点以在图纸上定位形状。
  3. 请族长创造形状。
  4. 设置形状类型(线条,椭圆形,矩形等...)
  5. 设置有关形状的任何其他样式细节。(例如:线条粗细等......)
 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);
  • 使用不同的调用创建文本框:
 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);
  • 可以使用不同的字体来设置文本框中文本的部分样式。这是如何做:
 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); //左上角,右下角

如果在组中创建组,它也将拥有自己的坐标空间。

造型形状 Styling Shapes

默认情况下,形状看起来有点简单。然而,可以对形状应用不同的样式。目前可以做的事情有:

  • 更改填充颜色。
  • 制作没有填充颜色的形状。
  • 改变线条的粗细。
  • 改变线条的样式。例如:虚线,点缀。
  • 更改线条颜色。

以下是如何完成此操作的示例:

 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);

形状和图形2d Shapes and Graphics2d

虽然本机POI形状绘制命令是在形状中绘制形状的推荐方法,但有时需要使用标准API来与外部库兼容。考虑到这一点,我们为Graphics和Graphics2d创建了一些包装器。

警告然而,重要的是,在继续之前, Graphics2d与Microsoft Office绘图命令的功能不匹配。较旧的 Graphics类提供了更接近的匹配,但仍然是圆孔中的方形挂钩。

所有Graphics命令都发布到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日志记录基础结构返回并记录消息(默认情况下禁用)。

大纲 Outlining

大纲非常适合将信息部分组合在一起,并且可以使用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 );

您选择的行/列应包含已创建的组。它可以在组内的任何地方。


图片 Images

图像是绘图支持的一部分。要添加图像,只需在绘图族长上调用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);
    }

警告:Picture.resize()仅适用于JPEG和PNG。其他格式尚不支持。

从工作簿中读取图像:

   List lst = workbook.getAllPictures();
    for (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);
          }
        }
    }

 命名范围和命名单元格

命名范围是一种通过名称引用一组单元格的方法。命名单元格是命名范围的简并情况,因为“单元格组”恰好包含一个单元格。您可以创建以及按命名范围引用工作簿中的单元格。使用命名范围时,使用类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(); //检索工作簿

     //检索命名范围
    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

从不连续的命名范围读取

 // Setup code
    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

请注意,删除单元格时,Excel不会删除附加的命名范围。因此,工作簿可以包含指向不再存在的单元格的命名范围。在构造AreaReference之前,您应该检查引用的有效性

  if(name.isDeleted()){
       //命名范围指向已删除的单元格。
    } else {
      AreaReference ref = new AreaReference(name.getRefersToFormula());
    }

 单元格评论 - HSSF和XSSF 

注释是附加到单元格并与单元格关联的富文本注释,与其他单元格内容分开。注释内容与单元格分开存储,并显示在与单元格分开但与之关联的图形对象(如文本框)中

 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 comments = sheet.getCellComments();
    Comment commentA1 = comments.get(new CellAddress(0, 0));
    Comment commentB1 = comments.get(new CellAddress(0, 1));
    for (Entry e : comments.entrySet()) {
      CellAddress loc = e.getKey();
      Comment comment = e.getValue();
      System.out.println("Comment at " + loc + ": " +
          "[" + comment.getAuthor() + "] " + comment.getString().getString());
    }
  

调整列宽以适合内容

  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);
    //如果您有列索引的集合,请参阅SXSSFSheet#trackColumnForAutoSizing(Collection )
    //或滚动您自己的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()不评估公式单元格,公式单元格的宽度是根据缓存的公式结果计算的。如果您的工作簿有很多公式,那么在自动调整大小之前评估它们是个好主意。

警告:计算列宽Sheet.autoSizeColumn使用Java2D类,如果图形环境不可用则抛出异常。如果图形环境不可用,您必须告诉Java您正在无头模式下运行并设置以下系统属性:java.awt.headless = true。您还应确保您在工作簿中使用的字体可用于Java。


 如何阅读超链接

  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);

    //单元格
    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("http://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);
    //note, if subject contains white spaces, make sure they are url-encoded
    link.setAddress("mailto:[email protected]?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();

 数据验证

从版本3.8开始,POI的语法略有不同,可以使用.xls和.xlsx格式的数据验证。

hssf.usermodel(二进制.xls格式)

检查用户根据一个或多个预定义值进入单元格的值。

以下代码将用户可以输入单元格A1的值限制为三个整数值10,20或30之一。

HSSFWorkbook workbook = new HSSFWorkbook();
  HSSFSheet sheet = workbook.createSheet("Data Validation");
  CellRangeAddressList addressList = new CellRangeAddressList(
    0, 0, 0, 0);
  DVConstraint dvConstraint = DVConstraint.createExplicitListConstraint(
    new String[]{"10", "20", "30"});
  DataValidation dataValidation = new HSSFDataValidation
    (addressList, dvConstraint);
  dataValidation.setSuppressDropDownArrow(true);
  sheet.addValidationData(dataValidation);

下拉列表

此代码将执行相同操作,但为用户提供一个下拉列表以从中选择值。

 HSSFWorkbook workbook = new HSSFWorkbook();
  HSSFSheet sheet = workbook.createSheet("Data Validation");
  CellRangeAddressList addressList = new CellRangeAddressList(
    0, 0, 0, 0);
  DVConstraint dvConstraint = DVConstraint.createExplicitListConstraint(
    new String[]{"10", "20", "30"});
  DataValidation dataValidation = new HSSFDataValidation
    (addressList, dvConstraint);
  dataValidation.setSuppressDropDownArrow(false);
  sheet.addValidationData(dataValidation);

错误消息

创建一个消息框,如果输入的值无效,将显示给用户。

 dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);
  dataValidation.createErrorBox("Box Title", "Message Text");

将“Box Title”替换为您希望在消息框标题栏中显示的文本,将“Message Text”替换为错误消息的文本。

提示

创建用户在包含数据验证的单元格获得焦点时将看到的提示

 dataValidation.createPromptBox("Title", "Message Text");
  dataValidation.setShowPromptBox(true);

封装在传递给createPromptBox()方法的第一个参数中的文本将显示为emboldened,并作为提示的标题,而第二个参数将显示为消息的文本。可以传递createExplicitListConstraint()方法,并传递包含整数,浮点,日期或文本值的String数组。

进一步的数据验证

要获得检查输入值的验证,例如,10到100之间的整数,请使用DVConstraint.createNumericConstraint(int,int,String,String)工厂方法。

  dvConstraint = DVConstraint.createNumericConstraint(
    DVConstraint.ValidationType.INTEGER,
    DVConstraint.OperatorType.BETWEEN, "10", "100");

查看其他验证和运算符类型的javadoc; 另请注意,此方法不支持所有验证类型。传递给两个String参数的值可以是公式; '='符号用于表示公式

 dvConstraint = DVConstraint.createNumericConstraint(
    DVConstraint.ValidationType.INTEGER,
    DVConstraint.OperatorType.BETWEEN, "=SUM(A1:A3)", "100");

如果调用createNumericConstraint()方法,则无法创建下拉列表,只会忽略setSuppressDropDownArrow(false)方法调用。

可以通过调用createDateConstraint(int,String,String,String)或createTimeConstraint(int,String,String)来创建日期和时间约束。两者都与上面非常类似,并在javadoc中进行了解释。

从电子表格单元格创建数据验证

特定单元格的内容可用于提供数据验证的值,DVConstraint.createFormulaListConstraint(String)方法支持此功能。要指定值来自连续范围的单元格,请执行以下任一操作:

 dvConstraint = DVConstraint.createFormulaListConstraint("$A$1:$A$3");

要么

 Name namedRange = workbook.createName();
  namedRange.setNameName("list1");
  namedRange.setRefersToFormula("$A$1:$A$3");
  dvConstraint = DVConstraint.createFormulaListConstraint("list1");

在这两种情况下,用户都可以从包含单元格A1,A2和A3中的值的下拉列表中进行选择。

数据不必作为数据验证。但是,要从其他工作表中选择数据,必须在创建工作表时为工作表指定名称,并且应在公式中使用该名称。因此假设存在名为“数据表”的工作表,这将起作用:

  Name namedRange = workbook.createName();
  namedRange.setNameName("list1");
  namedRange.setRefersToFormula("'Data Sheet'!$A$1:$A$3");
  dvConstraint = DVConstraint.createFormulaListConstraint("list1");

就像这样:

 dvConstraint = DVConstraint.createFormulaListConstraint("'Data Sheet'!$A$1:$A$3");

虽然这不会:

  Name namedRange = workbook.createName();
  namedRange.setNameName("list1");
  namedRange.setRefersToFormula("'Sheet1'!$A$1:$A$3");
  dvConstraint = DVConstraint.createFormulaListConstraint("list1");

这也不会:

 dvConstraint = DVConstraint.createFormulaListConstraint("'Sheet1'!$A$1:$A$3");

 xssf.usermodel(.xlsx格式)

当您创建基于xml的SpreadsheetML工作簿文件时,数据验证的工作方式类似; 但是有区别。例如,在一些地方需要显式强制类型转换,因为xssf流中对数据验证的支持已经内置到统一的ss流中,之后会更多。注意到代码中的其他差异。

检查用户根据一个或多个预定义值进入单元格的值

 XSSFWorkbook workbook = new XSSFWorkbook();
  XSSFSheet sheet = workbook.createSheet("Data Validation");
  XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheet);
  XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint)
    dvHelper.createExplicitListConstraint(new String[]{"11", "21", "31"});
  CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0);
  XSSFDataValidation validation =(XSSFDataValidation)dvHelper.createValidation(
    dvConstraint, addressList);

  //这里将布尔值false传递给setSuppressDropDownArrow()
  //方法。在上面的hssf.usermodel示例中,传递给此
  //方法的值为true。           
  validation.setSuppressDropDownArrow(false);

  //注意这个额外的方法调用。如果省略此方法调用,或者
  //传递布尔值false,则Excel将不验证
  //用户输入单元格的值。
  validation.setShowErrorBox(true);
  sheet.addValidationData(validation);

下拉列表

此代码将执行相同操作,但为用户提供一个下拉列表以从中选择值。

XSSFWorkbook workbook = new XSSFWorkbook();
  XSSFSheet sheet = workbook.createSheet("Data Validation");
  XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheet);
  XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint)
    dvHelper.createExplicitListConstraint(new String[]{"11", "21", "31"});
  CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0);
  XSSFDataValidation validation = (XSSFDataValidation)dvHelper.createValidation(
    dvConstraint, addressList);
  validation.setShowErrorBox(true);
  sheet.addValidationData(validation);

请注意,可以简单地排除对setSuppressDropDowmArrow()方法的调用,或者替换为:

  validation.setSuppressDropDownArrow(true);

提示和错误消息:

这些都与hssf.usermodel完全相同,因此请参阅上面的“错误消息:”和“提示:”部分。

进一步的数据验证:

要获得检查输入值的验证,例如,介于10和100之间的整数,请使用XSSFDataValidationHelper(s)createNumericConstraint(int,int,String,String)工厂方法。

XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint)
    dvHelper.createNumericConstraint(
      XSSFDataValidationConstraint.ValidationType.INTEGER,
      XSSFDataValidationConstraint.OperatorType.BETWEEN,
      "10", "100");

传递给最后两个String参数的值可以是公式; '='符号用于表示公式。因此,只有当它们落在两个单元格范围的求和结果之间时,以下才会创建允许值的验证

 XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint)
    dvHelper.createNumericConstraint(
      XSSFDataValidationConstraint.ValidationType.INTEGER,
      XSSFDataValidationConstraint.OperatorType.BETWEEN,
      "=SUM(A1:A10)", "=SUM(B24:B27)");

如果调用createNumericConstraint()方法,则无法创建下拉列表,只会忽略setSuppressDropDownArrow(true)方法调用。

请检查javadoc中是否有其他约束类型作为示例,这些将​​不包括在内。例如,在XSSFDataValidationHelper类上定义的方法允许您创建以下类型的约束; 日期,时间,小数,整数,数字,公式,文本长度和自定义约束。

从Spread Sheet单元格创建数据验证:

上面没有提到的另一种类型的约束是公式列表约束。它允许您创建一个验证,从一系列单元格中获取值。这段代码

XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint)
    dvHelper.createFormulaListConstraint("$A$1:$F$1");

将创建一个验证,从A1到F1范围内的单元格中获取值。

如果您使用这样的命名范围,可以扩展此技术的用途;

 XSSFName name = workbook.createName();
  name.setNameName("data");
  name.setRefersToFormula("$B$1:$F$1");
  XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheet);
  XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint)
    dvHelper.createFormulaListConstraint("data");
  CellRangeAddressList addressList = new CellRangeAddressList(
    0, 0, 0, 0);
  XSSFDataValidation validation = (XSSFDataValidation)
    dvHelper.createValidation(dvConstraint, addressList);
  validation.setSuppressDropDownArrow(true);
  validation.setShowErrorBox(true);
  sheet.addValidationData(validation);

OpenOffice Calc在名称范围方面的规则略有不同。Excel支持名称的Workbook和Sheet作用域,但Calc不支持,它似乎只支持名称的Sheet作用域。因此,通常最好完全限定区域或区域的名称;

 XSSFName name = workbook.createName();
  name.setNameName("data");
  name.setRefersToFormula("'Data Validation'!$B$1:$F$1");
  ....

然而,这确实打开了一个更有趣的机会,那就是将验证的所有数据放入工作簿中隐藏工作表的命名单元格范围内。然后可以在setRefersToFormula()方法参数中明确标识这些范围。


ss.usermodel

ss.usermodel包中的类允许开发人员创建可用于生成二进制(.xls)和SpreadsheetML(.xlsx)工作簿的代码。

用于创建数据验证的技术与上面的xssf.usermodel示例有很多共同之处。因此,这里只会展示一两个例子。

检查用户根据一个或多个预定义值进入单元格的值

  Workbook workbook = new XSSFWorkbook();  // or new HSSFWorkbook
  Sheet sheet = workbook.createSheet("Data Validation");
  DataValidationHelper dvHelper = sheet.getDataValidationHelper();
  DataValidationConstraint dvConstraint = dvHelper.createExplicitListConstraint(
    new String[]{"13", "23", "33"});
  CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0);            
  DataValidation validation = dvHelper.createValidation(
    dvConstraint, addressList);
  //注意检查DataValidation对象的实际类型。
  //如果它是XSSFDataValidation类的实例,那么
  //布尔值'false'
  //方法和对setShowErrorBox()方法的显式调用。
  if(validation instanceof XSSFDataValidation) {
    validation.setSuppressDropDownArrow(false);
    validation.setShowErrorBox(true);
  }
  else {
   //如果Datavalidation包含HSSFDataValidation 
    //类的实例,则应将'true'传递给setSuppressDropDownArrow()
    //方法,并且不需要调用setShowErrorBox()。
    validation.setSuppressDropDownArrow(true);
  }
  sheet.addValidationData(validation);

下拉列表

此代码将执行相同操作,但为用户提供一个下拉列表以从中选择值。

Workbook workbook = new XSSFWorkbook();  // or new HSSFWorkbook
  Sheet sheet = workbook.createSheet("Data Validation");
  DataValidationHelper dvHelper = sheet.getDataValidationHelper();
  DataValidationConstraint dvConstraint = dvHelper.createExplicitListConstraint(
    new String[]{"13", "23", "33"});
  CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0);            
  DataValidation validation = dvHelper.createValidation(
    dvConstraint, addressList);
  //注意检查DataValidation对象的实际类型。
  //如果它是XSSFDataValidation类的实例,那么
  //布尔值'false'
  //方法和对setShowErrorBox()方法的显式调用。
  if(validation instanceof XSSFDataValidation) {
    validation.setSuppressDropDownArrow(true);
    validation.setShowErrorBox(true);
  }
  else {
    //如果Datavalidation包含HSSFDataValidation 
    //类的实例,则应将'true'传递给setSuppressDropDownArrow()
    //方法,并且不需要调用setShowErrorBox()。
    validation.setSuppressDropDownArrow(false);
  }
  sheet.addValidationData(validation);

提示和错误消息

这些都与hssf.usermodel完全相同,因此请参阅上面的“错误消息:”和“提示:”部分。

由于ss.usermodel和xssf.usermodel示例之间的差异很小 - 主要限制于获取DataValidationHelper的方式,缺少任何需要显式转换数据类型以及hssf和xssf解释之间的行为差​​异很小setSuppressDropDowmArrow()方法,本节不会包含其他示例。

高级数据验证

依赖下拉列表

在某些情况下,可能需要向用户呈现包含多于一个下拉列表的表。此外,用户在一个下拉列表中做出的选择可能会影响在第二个或后续下拉列表中呈现给他们的选项。现在将解释可用于实现该行为的一种技术。

该技术有两个关键; 一种是使用命名区域或单元格区域来保存下拉列表的数据,第二种是使用INDIRECT()函数在名称和单元格的实际地址之间进行转换。在示例部分中有一个完整的工作示例 - 名为LinkedDropDownLists.java - 演示了如何创建链接或从属下拉列表。这里仅解释更相关的要点。

要创建两个下拉列表,其中第二个中显示的选项取决于第一个中所做的选择,首先创建一个命名的单元格区域,以保存用于填充第一个下拉列表的所有数据。接下来,创建一个数据验证,它将查找此命名区域的数据,如下所示;

CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0);
  DataValidationHelper dvHelper = sheet.getDataValidationHelper();
  DataValidationConstraint dvConstraint = dvHelper.createFormulaListConstraint(
    "CHOICES");
  DataValidation validation = dvHelper.createValidation(
    dvConstraint, addressList);
  sheet.addValidationData(validation);

请注意,区域的名称 - 在上面的示例中是'CHOICES' - 只是传递给createFormulaListConstraint()方法。这足以使Excel使用该命名区域中的数据填充下拉列表。

接下来,对于用户可以在第一个下拉列表中选择的每个选项,创建匹配的命名单元格区域。该区域的名称应与用户可在第一个下拉列表中选择的文本相匹配。注意,在该示例中,所有大写字母都用在单元格区域的名称中。

现在,非常相似的代码可用于创建第二个链接的下拉列表;

  CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 1, 1);
  DataValidationConstraint dvConstraint = dvHelper.createFormulaListConstraint(
    "INDIRECT(UPPER($A$1))");
  DataValidation validation = dvHelper.createValidation(
    dvConstraint, addressList);
  sheet.addValidationData(validation);

这里的关键是以下Excel函数 - INDIRECT(UPPER($ A $ 1)) - 用于填充第二个链接的下拉列表。从最里面的一对括号开始工作,它指示Excel查看单元格A1的内容,将其读取的内容转换为大写 - 大写字母用于每个区域的名称 - 然后转换此名称进入包含数据的单元格的地址,以填充另一个下拉列表。


嵌入对象

可以对嵌入的Excel,Word或PowerPoint文档执行更详细的处理,或者与任何其他类型的嵌入对象一起使用。

HSSF:

POIFSFileSystem fs = new POIFSFileSystem(new File("excel_with_embeded.xls"));
  HSSFWorkbook workbook = new HSSFWorkbook(fs);
  for (HSSFObjectData obj : workbook.getAllEmbeddedObjects()) {
      //对象的OLE2类名
      String oleName = obj.getOLE2ClassName();
      if (oleName.equals("Worksheet")) {
          DirectoryNode dn = (DirectoryNode) obj.getDirectory();
          HSSFWorkbook embeddedWorkbook = new HSSFWorkbook(dn, false);
          //System.out.println(entry.getName() + ": " + embeddedWorkbook.getNumberOfSheets());
      } else if (oleName.equals("Document")) {
          DirectoryNode dn = (DirectoryNode) obj.getDirectory();
          HWPFDocument embeddedWordDocument = new HWPFDocument(dn);
          //System.out.println(entry.getName() + ": " + embeddedWordDocument.getRange().text());
      }  else if (oleName.equals("Presentation")) {
          DirectoryNode dn = (DirectoryNode) obj.getDirectory();
          SlideShow embeddedPowerPointDocument = new HSLFSlideShow(dn);
          //System.out.println(entry.getName() + ": " + embeddedPowerPointDocument.getSlides().length);
      } else {
          if(obj.hasDirectoryEntry()){
              // DirectoryEntry是DocumentNode。检查其条目以找出它是什么
              DirectoryNode dn = (DirectoryNode) obj.getDirectory();
              for (Entry entry : dn) {
                  //System.out.println(oleName + "." + entry.getName());
              }
          } else {
              //没有DirectoryEntry 
              //从HSSFObjectData实例中恢复对象的数据。
              byte[] objectData = obj.getObjectData();
          }
      }
  }

XSSF:

 XSSFWorkbook workbook = new XSSFWorkbook("excel_with_embeded.xlsx");
  for (PackagePart pPart : workbook.getAllEmbeddedParts()) {
      String contentType = pPart.getContentType();
      // Excel工作簿 - 二进制或OpenXML 
      if (contentType.equals("application/vnd.ms-excel")) {
          HSSFWorkbook embeddedWorkbook = new HSSFWorkbook(pPart.getInputStream());
      }
      // // Excel工作簿 - 否则为OpenXML文件格式
      else if (contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
          OPCPackage docPackage = OPCPackage.open(pPart.getInputStream());
          XSSFWorkbook embeddedWorkbook = new XSSFWorkbook(docPackage);
      }
      // Word文档 - 二进制(OLE2CDF)文件格式
      else if (contentType.equals("application/msword")) {
          HWPFDocument document = new HWPFDocument(pPart.getInputStream());
      }
      // Word文档 - 否则为OpenXML文件格式
      else if (contentType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
          OPCPackage docPackage = OPCPackage.open(pPart.getInputStream());
          XWPFDocument document = new XWPFDocument(docPackage);
      }
      // PowerPoint文档 - 二进制文件格式
      else if (contentType.equals("application/vnd.ms-powerpoint")) {
          HSLFSlideShow slideShow = new HSLFSlideShow(pPart.getInputStream());
      }
      // PowerPoint文档 -  OpenXML文件格式
      else if (contentType.equals("application/vnd.openxmlformats-officedocument.presentationml.presentation")) {
          OPCPackage docPackage = OPCPackage.open(pPart.getInputStream());
          XSLFSlideShow slideShow = new XSLFSlideShow(docPackage);
      }
      //任何其他类型的嵌入对象。
      else {
          System.out.println("Unknown Embedded Document: " + contentType);
          InputStream inputStream = pPart.getInputStream();
      }
  }

(自POI-3.7起)


自动筛选

 Workbook wb = new HSSFWorkbook(); //or new XSSFWorkbook();
    Sheet sheet = wb.createSheet();
    sheet.setAutoFilter(CellRangeAddress.valueOf("C5:F200"));

条件格式

 Workbook workbook = new HSSFWorkbook(); // or new XSSFWorkbook();
    Sheet sheet = workbook.createSheet();

    SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();

    ConditionalFormattingRule rule1 = sheetCF.createConditionalFormattingRule(ComparisonOperator.EQUAL, "0");
    FontFormatting fontFmt = rule1.createFontFormatting();
    fontFmt.setFontStyle(true, false);
    fontFmt.setFontColorIndex(IndexedColors.DARK_RED.index);
    
    BorderFormatting bordFmt = rule1.createBorderFormatting();
    bordFmt.setBorderBottom(BorderStyle.THIN);
    bordFmt.setBorderTop(BorderStyle.THICK);
    bordFmt.setBorderLeft(BorderStyle.DASHED);
    bordFmt.setBorderRight(BorderStyle.DOTTED);

    PatternFormatting patternFmt = rule1.createPatternFormatting();
    patternFmt.setFillBackgroundColor(IndexedColors.YELLOW.index);

    ConditionalFormattingRule rule2 = sheetCF.createConditionalFormattingRule(ComparisonOperator.BETWEEN, "-10", "10");
    ConditionalFormattingRule [] cfRules =
    {
        rule1, rule2
    };

    CellRangeAddress[] regions = {
        CellRangeAddress.valueOf("A3:A5")
    };

    sheetCF.addConditionalFormatting(regions, cfRules);

在ConditionalFormats.java中查看有关Excel条件格式的更多示例


隐藏和不隐藏的行

使用Excel,可以通过选择该行(或多行)隐藏工作表上的行,右键单击鼠标右键一次,然后从出现的弹出菜单中选择“隐藏”。

要使用POI模拟它,只需在XSSFRow或HSSFRow的实例上调用setZeroHeight()方法(该方法在两个类实现的ss.usermodel.Row接口上定义),如下所示:

 Workbook workbook = new XSSFWorkbook();  // OR new HSSFWorkbook()
  Sheet sheet = workbook.createSheet(0);
  Row row = workbook.createRow(0);
  row.setZeroHeight();

如果文件现在已保存到光盘,则第一张纸上的第一行将不可见。

使用Excel,可以通过选择上面的行和隐藏的行下面的行来取消隐藏先前隐藏的行,然后按住Ctrl键,按住Shift键并按下数字9,然后释放所有行。

要使用POI模拟此行为,请执行以下操作:

  Workbook workbook = WorkbookFactory.create(new File(.......));
  Sheet = workbook.getSheetAt(0);
  Iterator row Iter = sheet.iterator();
  while(rowIter.hasNext()) {
    Row row = rowIter.next();
    if(row.getZeroHeight()) {
      row.setZeroHeight(false);
    }
  }

如果文件现在已保存到光盘,则现在可以看到工作簿第一张表上任何以前隐藏的行。

该示例说明了两个功能。首先,可以通过调用setZeroHeight()方法并传递布尔值'false'来取消隐藏行。其次,它说明了如何测试行是否隐藏。只需调用getZeroHeight()方法,如果隐藏了行,它将返回'true',否则返回'false'。


设置单元格属性

有时,使用基本样式创建电子表格更容易或更有效,然后将特殊样式应用于某些单元格,例如围绕一系列单元格绘制边框或设置区域的填充。CellUtil.setCellProperties允许您在不在电子表格中创建一堆不必要的中间样式的情况下执行此操作。

属性创建为Map,并以下列方式应用于单元格。

 Workbook workbook = new XSSFWorkbook();  // OR new HSSFWorkbook()
  Sheet sheet = workbook.createSheet("Sheet1");
  Map properties = new HashMap();
		  
  //一个单元格的
  properties.put(CellUtil.BORDER_TOP, BorderStyle.MEDIUM);
  properties.put(CellUtil.BORDER_BOTTOM, BorderStyle.MEDIUM);
  properties.put(CellUtil.BORDER_LEFT, BorderStyle.MEDIUM);
  properties.put(CellUtil.BORDER_RIGHT, BorderStyle.MEDIUM);
  
  //给它一个颜色(RED)
  properties.put(CellUtil.TOP_BORDER_COLOR, IndexedColors.RED.getIndex());
  properties.put(CellUtil.BOTTOM_BORDER_COLOR, IndexedColors.RED.getIndex());
  properties.put(CellUtil.LEFT_BORDER_COLOR, IndexedColors.RED.getIndex());
  properties.put(CellUtil.RIGHT_BORDER_COLOR, IndexedColors.RED.getIndex());
		  
  //将边框应用于B2 
  Row row = sheet.createRow(1);
  Cell cell = row.createCell(1);
  CellUtil.setCellStyleProperties(cell, properties);
   		  
 //将边框应用于从D4开始的3x3区域
  for (int ix=3; ix <= 5; ix++) {
    row = sheet.createRow(ix);
    for (int iy = 3; iy <= 5; iy++) {
      cell = row.createCell(iy);
      CellUtil.setCellStyleProperties(cell, properties);
    }
  }

注意:这不会替换单元格的属性,它会将您放入Map的属性与单元格的现有样式属性合并。如果属性已存在,则将其替换为新属性。如果某个属性不存在,则会添加该属性。此方法不会删除CellStyle属性。


绘图边框

在Excel中,只需按一下按钮,即可在整个工作簿区域上应用一组边框。PropertyTemplate对象使用定义的方法和常量来模拟这一点,以允许绘制一系列单元格的顶部,底部,左侧,右侧,水平,垂直,内部,外部或所有边框。其他方法允许将颜色应用于边界。

它的工作方式如下:您创建一个PropertyTemplate对象,该对象是您希望应用于工作表的边框的容器。然后,您将边框和颜色添加到PropertyTemplate,最后将其应用于您需要该组边框的任何工作表。您可以创建多个PropertyTemplate对象并将它们应用于单个工作表,也可以将同一PropertyTemplate对象应用于多个工作表。它就像一个预印表格。

枚举:

边框

定义边框的外观,无论是厚或薄,实心还是虚线,单面或双面。此枚举替换了已弃用的CellStyle.BORDER_XXXXX常量。PropertyTemplate不支持旧样式BORDER_XXXXX常量。BorderStyle.NONE的特殊值将在应用单元格后从其中删除边框。

BorderExtent

描述BorderStyle将应用于的区域部分。例如,TOP,BOTTOM,INSIDE或OUTSIDE。BorderExtent.NONE的特殊值将从PropertyTemplate中删除边框。应用模板时,不会对PropertyTemplate中不存在边框属性的单元格边框进行任何更改。

 //绘制边框(三个3x3网格)
  PropertyTemplate pt = new PropertyTemplate();
   //#1)这些边框在默认颜色
  pt.drawBorders(new CellRangeAddress(1, 3, 1, 3),
          BorderStyle.MEDIUM, BorderExtent.ALL);
  //#2)这些单元格将具有中等外边框和内边框薄
  pt.drawBorders(new CellRangeAddress(5, 7, 1, 3),
          BorderStyle.MEDIUM, BorderExtent.OUTSIDE);
  pt.drawBorders(new CellRangeAddress(5, 7, 1, 3), BorderStyle.THIN,
          BorderExtent.INSIDE);
  //#3)这些细胞都是中等重量的,具有不同颜色的
  //外部,内部水平和内部垂直边界。中心
  //单元格没有边框。
  pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
          BorderStyle.MEDIUM, IndexedColors.RED.getIndex(),
          BorderExtent.OUTSIDE);
  pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
          BorderStyle.MEDIUM, IndexedColors.BLUE.getIndex(),
          BorderExtent.INSIDE_VERTICAL);
  pt.drawBorders(new CellRangeAddress(9, 11, 1, 3),
          BorderStyle.MEDIUM, IndexedColors.GREEN.getIndex(),
          BorderExtent.INSIDE_HORIZONTAL);
  pt.drawBorders(new CellRangeAddress(10, 10, 2, 2),
          BorderStyle.NONE, 
          BorderExtent.ALL);

  //将边框应用于工作表
  Workbook wb = new XSSFWorkbook();
  Sheet sh = wb.createSheet("Sheet1");
  pt.applyBorders(sh);

注意:最后一个pt.drawBorders()调用使用BorderStyle.NONE从范围中删除边框。与setCellStyleProperties类似,applyBorders方法合并单元格样式的属性,因此仅当现有边框被其他内容替换时才会更改现有边框,或者仅当它们被BorderStyle.NONE替换时才会被删除。要从边框中删除颜色,请使用IndexedColor.AUTOMATIC.getIndex()。

此外,要从PropertyTemplate对象中删除边框或颜色,请使用BorderExtent.NONE。

这不适用于对角线边界。


创建数据透视表

数据透视表是电子表格文件的强大功能。您可以使用以下代码创建数据透视表。

 XSSFWorkbook wb = new XSSFWorkbook();
  XSSFSheet sheet = wb.createSheet();

  //创建一些数据以便在
  setCellData(sheet);

  XSSFPivotTable pivotTable = sheet.createPivotTable(new AreaReference("A1:D4"), new CellReference("H5"));
  //配置数据透视表
  //使用第一列作为行标签
  pivotTable.addRowLabel(0);
   //总结第二列
  pivotTable.addColumnLabel(DataConsolidateFunction.SUM, 1);
  /将第三列设置为过滤器
  pivotTable.addColumnLabel(DataConsolidateFunction.AVERAGE, 2);
  //在第四列pivotTable.addReportFilter(3)上添加过滤器;
  pivotTable.addReportFilter(3);

具有多种样式的单元格(富文本字符串)

要将单组文本格式(颜色,样式,字体等)应用于单元格,您应该 为工作簿创建 CellStyle,然后应用于单元格。

 // HSSF 示例
  HSSFCell hssfCell = row.createCell(idx);
  //rich text consists of two runs
  HSSFRichTextString richString = new HSSFRichTextString( "Hello, World!" );
  richString.applyFont( 0, 6, font1 );
  richString.applyFont( 6, 13, font2 );
  hssfCell.setCellValue( richString );


  // XSSF 示例
  XSSFCell cell = row.createCell(1);
  XSSFRichTextString rt = new XSSFRichTextString("The quick brown fox");

  XSSFFont font1 = wb.createFont();
  font1.setBold(true);
  font1.setColor(new XSSFColor(new java.awt.Color(255, 0, 0)));
  rt.applyFont(0, 10, font1);

  XSSFFont font2 = wb.createFont();
  font2.setItalic(true);
  font2.setUnderline(XSSFFont.U_DOUBLE);
  font2.setColor(new XSSFColor(new java.awt.Color(0, 255, 0)));
  rt.applyFont(10, 19, font2);

  XSSFFont font3 = wb.createFont();
  font3.setColor(new XSSFColor(new java.awt.Color(0, 0, 255)));
  rt.append(" Jumped over the lazy dog", font3);

  cell.setCellValue(rt);

要将不同的格式应用于单元格的不同部分,您需要使用 RichTextString,它允许在单元格内部分文本样式。

HSSF和XSSF之间存在一些细微差别,特别是在字体颜色周围(两种格式在内部存储颜色完全不同),请参阅 HSSF富文本字符串 和 XSSF富文本字符串 javadocs以获取更多详细信息。


新的通用SS Usermodel代码(支持全部excel版本)

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

Workbook[] wbs = new Workbook[] { new HSSFWorkbook(), new XSSFWorkbook() };
for(int i=0; i

 

你可能感兴趣的:(spring,boot,poi,excel)