java 系读写 Excel 文件既可以用 jxl 库, 也可以用 POI 库, 但是, jxl 库只支持低版本的 excel2003, 不支持更高版本, 无法直接输出 *.xlsx 文件, 只能输出 *.xls 文件, 另外, 更新也不频繁. 所以, 目前大多采用 POI 库.
jxl 库官网: http://jxl.sourceforge.net/
POI 介绍
要想使用 POI 对 Excel 进行操作, 我们需要先了解一下 Excel 的两种版本: 一种是 97-2003 版本扩展名是 ".xls"; 一种是 2007 版本扩展名是 ".xlsx".POI 分别针对这两种版本需要导入的 jar 包不同, 操作类也不同.
HSSF: 操作的是. xls;XSSF: 操作的是. xlsx.
不管哪种操作, 基本思路都是一致, 先要对应一个 Excel 文件, 然后在对应文件中的某个 sheet, 接下来在操作某一行和这一行中的某一列. 对应 POI 包: 文件 (webbook),sheet(sheet), 行(row) 和具体单元格(cell).
详细操作请参照 POI 官网的 Excel(HSSF/XSSF) https://poi.apache.org/ 操作. 此外, 还有 EasyPOI http://easypoi.mydoc.io/ , 功能与 POI 差不多, Easypoi 的目标不是替代 poi, 而是让一个不懂导入导出的快速使用 poi 完成 Excel 和 Word 的各种操作, 而不是看很多 API 才可以完成这样工作.
下面给出我的测试用例源码.
1, 将工程所需要的 poi 库 (本测试的版本 poi-bin-4.1.2-20200217.zip) 中的 lib 文件添加进来, 并添加到 Build Path 中, 如下图:
2, 工程源代码:
- package com.reus;
- import java.awt.BorderLayout;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.math.BigDecimal;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.TimeZone;
- import javax.swing.JButton;
- import javax.swing.JFrame;
- import javax.swing.JPanel;
- import javax.swing.JScrollPane;
- import javax.swing.JTable;
- import javax.swing.table.DefaultTableModel;
- import javax.swing.table.TableModel;
- import org.apache.poi.ss.usermodel.Cell;
- import org.apache.poi.ss.usermodel.CellType;
- import org.apache.poi.ss.usermodel.DateUtil;
- import org.apache.poi.xssf.usermodel.XSSFCell;
- import org.apache.poi.xssf.usermodel.XSSFRow;
- import org.apache.poi.xssf.usermodel.XSSFSheet;
- import org.apache.poi.xssf.usermodel.XSSFWorkbook;
- public class ExcelOperate {
- public static void main(String[] args) {
- String[][] data = { { "中文", "$1275.00" }, { "Pets", "$125.00" }, { "Electronics", "$2533.00" }, { "Mensware", "$497.00" } };
- String[] headers = { "Department", "Daily Revenue" };
- JFrame frame = new JFrame("JTable to Excel Hack");
- DefaultTableModel model = new DefaultTableModel(data, headers);
- final JTable table = new JTable(model);
- JScrollPane scroll = new JScrollPane(table);
- String outFullPath = "out.xlsx";// 默认输出到工程本地目录下
- JButton exportButton = new JButton("输出");// 输出为 Excel 文件
- exportButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent evt) {
- try {
- createExcel(model,outFullPath);// 输出并创建 Excel
- } catch (Exception ex) {
- System.out.println(ex.getMessage());
- ex.printStackTrace();
- }
- }
- });
- JButton readButton = new JButton("读取");// 读取 Excel 文件, 在控制台窗口打印显示
- readButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent evt) {
- try {
- SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss:SS");
- TimeZone t = sdf.getTimeZone();
- t.setRawOffset(0);
- sdf.setTimeZone(t);
- Long startTime = System.currentTimeMillis();// 用于计算从 Excel 文件中读取数据耗时
- String fileName = "in.xlsx";
- readExcel(fileName);// 读取 Excel,xlsx 后缀名的文件
- Long endTime = System.currentTimeMillis();
- System.out.println("用时:" + sdf.format(new Date(endTime - startTime)));
- } catch (Exception ex) {
- System.out.println(ex.getMessage());
- ex.printStackTrace();
- }
- }
- });
- JPanel bottomPanel=new JPanel();
- bottomPanel.setLayout(new BorderLayout());
- bottomPanel.add(exportButton, BorderLayout.NORTH);
- bottomPanel.add(readButton, BorderLayout.SOUTH);
- frame.getContentPane().add("Center", scroll);
- frame.getContentPane().add("South", bottomPanel);
- frame.pack();
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setVisible(true);
- }
- @SuppressWarnings({ "resource"})
- public static void readExcel(String strPath) throws IOException {
- // 构造 XSSFWorkbook 对象, strPath 传入文件路径
- XSSFWorkbook xwb = new XSSFWorkbook(strPath);
- // 读取第一个表格内容
- XSSFSheet sheet = xwb.getSheetAt(0);//0 表示第一个表格
- // 定义 row,cell
- XSSFRow row;
- XSSFCell cell;
- // 循环输出表格中的内容
- for (int i = sheet.getFirstRowNum(); i < sheet.getPhysicalNumberOfRows(); i++) {
- row = sheet.getRow(i);
- for (int j = row.getFirstCellNum(); j < row.getPhysicalNumberOfCells(); j++) {
- String ret = "";
- cell=row.getCell(j);
- ret = getCellValueByCell(cell);
- System.out.print(ret + "\t");
- }
- System.out.println("");
- }
- }
- // 获取单元格各类型值, 返回字符串类型
- public static String getCellValueByCell(Cell cell) {
- // 判断是否为 null 或空串
- if (cell == null || cell.toString().trim().equals("")) {
- return "";
- }
- String cellValue = "";
- CellType cellType = cell.getCellType();
- switch (cellType) {
- case NUMERIC:// 把枚举常量前的冗余类信息去掉编译即可通过
- short format = cell.getCellStyle().getDataFormat();
- if (DateUtil.isCellDateFormatted(cell)) {// 注意: DateUtil.isCellDateFormatted()方法对 "2019 年 1 月 18 日" 这种格式的日期, 判断会出现问题, 需要另行处理
- SimpleDateFormat sdf = null;
- // System.out.println("cell.getCellStyle().getDataFormat()="+cell.getCellStyle().getDataFormat());
- if (format == 20 || format == 32) {
- sdf = new SimpleDateFormat("HH:mm");
- } else if (format == 14 || format == 31 || format == 57 || format == 58) {
- // 处理自定义日期格式: m 月 d 日(通过判断单元格的格式 id 解决, id 的值是 58)
- sdf = new SimpleDateFormat("yyyy-MM-dd");
- double value = cell.getNumericCellValue();
- Date date = org.apache.poi.ss.usermodel.DateUtil.getJavaDate(value);
- cellValue = sdf.format(date);
- } else {// 日期
- sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- }
- try {
- cellValue = sdf.format(cell.getDateCellValue());// 日期
- } catch (Exception e) {
- try {
- throw new Exception("exception on get date data !".concat(e.toString()));
- } catch (Exception e1) {
- e1.printStackTrace();
- }
- } finally {
- sdf = null;
- }
- } else {
- BigDecimal bd = new BigDecimal(cell.getNumericCellValue());
- cellValue = bd.toPlainString();// 数值 这种用 BigDecimal 包装再获取 plainString, 可以防止获取到科学计数值
- }
- break;
- case STRING: // 字符串
- cellValue = cell.getStringCellValue();
- break;
- case BOOLEAN: // Boolean
- cellValue = cell.getBooleanCellValue() + "";
- break;
- case FORMULA: // 公式
- {
- // cellValue = cell.getCellFormula();// 读取单元格中的公式
- cellValue = String.valueOf(cell.getNumericCellValue());// 读取单元格中的数值
- }
- break;
- case BLANK: // 空值
- cellValue = "";
- break;
- case ERROR: // 故障
- cellValue = "ERROR VALUE";
- break;
- default:
- cellValue = "UNKNOW VALUE";
- break;
- }
- return cellValue;
- }
- /**
- * 用户列表导出, 生成 Excel
- */
- private static void createExcel(TableModel model, String outFileFullPath) {
- XSSFWorkbook userListExcel = createUserListExcel(model);
- try {
- // 输出成文件
- FileOutputStream outputStream = new FileOutputStream(new File(outFileFullPath));
- userListExcel.write(outputStream);
- outputStream.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 创建 Excel
- */
- private static XSSFWorkbook createUserListExcel(TableModel model) {
- // 1. 创建 HSSFWorkbook, 一个 HSSFWorkbook 对应一个 Excel 文件
- XSSFWorkbook wb = new XSSFWorkbook();
- // 2. 在 workbook 中添加一个 sheet, 对应 Excel 文件中的 sheet
- XSSFSheet sheet = wb.createSheet("sheet1");
- // 3. 设置表头, 即每个列的列名
- XSSFRow row = sheet.createRow(0);// 创建第一行
- for (int i = 0; i < model.getColumnCount(); i++) {
- row.createCell(i).setCellValue(model.getColumnName(i));// 给列写入数据, 创建单元格, 将列名写入
- }
- // 写入正式数据
- for (int i = 1; i <= model.getRowCount(); i++) {// 先行索引. 由于第一行已经被表格的标题占据了, 所以昌数据索引从 1 开始
- row = sheet.createRow(i);// 创建真正的行用于存放数据
- for (int j = 0; j < model.getColumnCount(); j++) {// 后列索引
- row.createCell(j).setCellValue(model.getValueAt(i-1, j).toString());
- sheet.autoSizeColumn(1, true);
- }
- }
- return wb;
- }
- }
3, 运行结果
主界面:
输出结果:
输入结果:
说明:
上文中的 in.xlsx 和 out.xlsx 均在工程当前目录下, 如下图所示:
参考文献:
1,
2,JAVA 实现数据库数据导入 / 导出到 Excel(POI) https://www.cnblogs.com/azhqiang/p/3688895.html
3,java 使用 POI 将数据导出放入 Excel
4,Excel 导入时, 日期格式的判断 isCellDateFormatted(Cell cell)不成功原因
5,java 通过 poi 读取 Excel 中的日期类型数据或自定义类型日期
6,poi 读取 Excel 时日期为数字 的解决方法
来源: http://www.bubuko.com/infodetail-3465056.html