Java基础系列19:使用JXL或者POI生成和解析Excel文件

一 简介

如题所示,当我们需要在Java中解析Excel文件时,可以考虑使用JXL或POI的API来解析。

二者的区别如下:

  • jxl现在基本上没被维护了,最近一次更新时间还是几年前。相反,poi属于Apache开源项目的一部分,更新维护得比较好,最新稳定版 POI 3.15 是今年(2016年)9月更新的,同时poi可以支持更高版本的excel,而jxl只能支持excel2003以及之前的版本
  • 小文件使用jxl解析效率比较高,但是因为支持的excel版本的限制,导致不能导出65535以上量级的数据

总之,我建议使用POI来生成解析excel文件。关于生成和解析excel文件的流程实际上跟Java生成和解析xml文件(PS:关于这部分的内容可以参考我的这篇文章:https://www.zifangsky.cn/596.html)是差不多的,因此我下面就直接贴示例代码了。当然,代码里面有详细的注释供大家参考

二 使用JXL生成和解析Excel文件

jxl-2.6.12.jar下载地址:http://maven.outofmemory.cn/net.sourceforge.jexcelapi/jxl/2.6/

package cn.zifangsky.excel;

import java.io.File;

import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.write.Label;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;

public class JXLDemo {

	/**
	 * JXL创建Excel文件
	 * 
	 * @param fileUrl
	 *            文件路径
	 * @return null
	 */
	public static void createExcel(String fileUrl) {
		String[] title = { "title1", "title2", "title3" };
		// 创建Excel文件
		File firstExcelFile = new File(fileUrl);

		try {
			// 创建工作簿
			WritableWorkbook workbook = Workbook.createWorkbook(firstExcelFile);
			// 创建sheet
			WritableSheet sheet = workbook.createSheet("demo", 0);
			Label label = null; // 单元格
			// 设置第一行的标题
			for (int i = 0; i < title.length; i++) {
				label = new Label(i, 0, title[i]);
				sheet.addCell(label);
			}

			// 添加几行数据
			for (int i = 0; i < title.length; i++) {
				for (int j = 1; j < 11; j++) {
					label = new Label(i, j, String.valueOf(i + j));
					sheet.addCell(label);
				}
			}
			workbook.write();
			workbook.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * JXL解析Excel文件
	 * 
	 * @param fileUrl
	 *            文件路径
	 * @return null
	 */
	public static void resolveExcel(String fileUrl) {
		try {
			Workbook workbook = Workbook.getWorkbook(new File(fileUrl));
			// 获取工作表中的第一个sheet
			Sheet sheet = workbook.getSheet(0);
			for (int i = 0; i < sheet.getRows(); i++) {
				for (int j = 0; j < sheet.getColumns(); j++) {
					Cell cell = sheet.getCell(j, i);
					System.out.print(cell.getContents() + " ");
				}
				System.out.println();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void main(String[] args) {
		JXLDemo.createExcel("C:/Users/Administrator/Desktop/jxlExcel.xls");
		JXLDemo.resolveExcel("C:/Users/Administrator/Desktop/jxlExcel.xls");
	}

}

生成的excel文件如下所示:

最后输出如下:

title1 title2 title3 
1 2 3 
2 3 4 
3 4 5 
4 5 6 
5 6 7 
6 7 8 
7 8 9 
8 9 10 
9 10 11 
10 11 12

三 使用POI生成和解析Excel文件

jar包下载地址:http://poi.apache.org/download.html

(1)生成和解析低版本的Excel文件:

package cn.zifangsky.excel;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

public class POIDemo {

	/**
	 * POI创建Excel文件
	 * 
	 * @param fileUrl
	 *            文件路径
	 * @return null
	 */
	public static void createExcel(String fileUrl) {
		String[] title = { "title1", "title2", "title3" };

		// 创建工作簿
		HSSFWorkbook workbook = new HSSFWorkbook();
		// 创建sheet
		HSSFSheet sheet = workbook.createSheet("demo");

		// 设置第一行的标题
		HSSFRow firstRow = sheet.createRow(0);
		HSSFCell cell = null;
		for (int i = 0; i < title.length; i++) {
			cell = firstRow.createCell(i);
			cell.setCellValue(title[i]);
		}

		// 添加几行数据
		for (int i = 0; i < 10; i++) {
			HSSFRow nextRow = sheet.createRow(i + 1);
			for (int j = 0; j < title.length; j++) {
				cell = nextRow.createCell(j);
				cell.setCellValue(i * j);
			}
		}

		// 创建Excel文件
		File POIExcelFile = new File(fileUrl);
		try {
			POIExcelFile.createNewFile();
			OutputStream outputStream = new FileOutputStream(POIExcelFile);
			workbook.write(outputStream);

			outputStream.close();
			workbook.close();
		} catch (IOException e) {

			e.printStackTrace();
		}
	}

	/**
	 * POI解析Excel文件
	 * 
	 * @param fileUrl
	 *            文件路径
	 * @return null
	 */
	public static void resolveExcel(String fileUrl) {
		File POIExcelFile = new File(fileUrl);
		try {
			InputStream inputStream = new FileInputStream(POIExcelFile);
			// 创建工作簿
			HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
			// 创建sheet
			// HSSFSheet sheet = workbook.getSheetAt(0);
			HSSFSheet sheet = workbook.getSheet("demo");

			int firstRowNum = sheet.getFirstRowNum(); // 第一行的行号
			int lastRowNum = sheet.getLastRowNum(); // 最后一行的行号
			// 循环遍历每一个单元格
			for (int row = firstRowNum; row <= lastRowNum; row++) {
				HSSFRow eachRow = sheet.getRow(row); // 每一行
				int firstCellNum = eachRow.getFirstCellNum(); // 第一列的列号
				int lastCellNum = eachRow.getLastCellNum(); // 最后一列的列号
				for (int column = firstCellNum; column < lastCellNum; column++) {
					HSSFCell cell = eachRow.getCell(column);
					if (row == 0)
						System.out.print(cell.getStringCellValue() + " ");
					else
						System.out.print(cell.getNumericCellValue() + " ");
				}
				System.out.println();
			}
			workbook.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		POIDemo.createExcel("C:/Users/Administrator/Desktop/poiExcel.xls");
		POIDemo.resolveExcel("C:/Users/Administrator/Desktop/poiExcel.xls");
	}

}

生成的excel文件如下:

控制台输出如下:

title1 title2 title3 
0.0 0.0 0.0 
0.0 1.0 2.0 
0.0 2.0 4.0 
0.0 3.0 6.0 
0.0 4.0 8.0 
0.0 5.0 10.0 
0.0 6.0 12.0 
0.0 7.0 14.0 
0.0 8.0 16.0 
0.0 9.0 18.0

(2)生成和解析高版本的Excel文件:

其实使用POI生成高版本的excel文件,只需要将HSSFWorkbook、HSSFSheet、HSSFRow、HSSFCell等类分别替换成:XSSFWorkbook、XSSFSheet、XSSFRow、XSSFCell等类即可,也就是将每个类最前面的“H”换成“X”即可

示例代码如下:

package cn.zifangsky.excel;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

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 POIDemo2 {

	/**
	 * POI创建高版本Excel文件
	 * 
	 * @param fileUrl
	 *            文件路径
	 * @return null
	 */
	public static void createExcel(String fileUrl) {
		String[] title = { "title1", "title2", "title3" };

		// 创建工作簿
		XSSFWorkbook workbook = new XSSFWorkbook();
		// 创建sheet
		XSSFSheet sheet = workbook.createSheet("demo");

		// 设置第一行的标题
		XSSFRow firstRow = sheet.createRow(0);
		XSSFCell cell = null;
		for (int i = 0; i < title.length; i++) {
			cell = firstRow.createCell(i);
			cell.setCellValue(title[i]);
		}

		// 添加几行数据
		for (int i = 0; i < 10; i++) {
			XSSFRow nextRow = sheet.createRow(i + 1);
			for (int j = 0; j < title.length; j++) {
				cell = nextRow.createCell(j);
				cell.setCellValue(i * j);
			}
		}

		// 创建Excel文件
		File POIExcelFile = new File(fileUrl);
		try {
			POIExcelFile.createNewFile();
			OutputStream outputStream = new FileOutputStream(POIExcelFile);
			workbook.write(outputStream);

			outputStream.close();
			workbook.close();
		} catch (IOException e) {

			e.printStackTrace();
		}
	}

	/**
	 * POI解析高版本Excel文件
	 * 
	 * @param fileUrl
	 *            文件路径
	 * @return null
	 */
	public static void resolveExcel(String fileUrl) {
		File POIExcelFile = new File(fileUrl);
		try {
			InputStream inputStream = new FileInputStream(POIExcelFile);
			// 创建工作簿
			XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
			// 创建sheet
			// HSSFSheet sheet = workbook.getSheetAt(0);
			XSSFSheet sheet = workbook.getSheet("demo");

			int firstRowNum = sheet.getFirstRowNum(); // 第一行的行号
			int lastRowNum = sheet.getLastRowNum(); // 最后一行的行号
			// 循环遍历每一个单元格
			for (int row = firstRowNum; row <= lastRowNum; row++) {
				XSSFRow eachRow = sheet.getRow(row); // 每一行
				int firstCellNum = eachRow.getFirstCellNum(); // 第一列的列号
				int lastCellNum = eachRow.getLastCellNum(); // 最后一列的列号
				for (int column = firstCellNum; column < lastCellNum; column++) {
					XSSFCell cell = eachRow.getCell(column);
					if (row == 0)
						System.out.print(cell.getStringCellValue() + " ");
					else
						System.out.print(cell.getNumericCellValue() + " ");
				}
				System.out.println();
			}
			workbook.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		POIDemo2.createExcel("C:/Users/Administrator/Desktop/poiExcel2.xlsx");
		POIDemo2.resolveExcel("C:/Users/Administrator/Desktop/poiExcel2.xlsx");
	}

}

生成的excel文件如下:

最后输出如下:

title1 title2 title3 
0.0 0.0 0.0 
0.0 1.0 2.0 
0.0 2.0 4.0 
0.0 3.0 6.0 
0.0 4.0 8.0 
0.0 5.0 10.0 
0.0 6.0 12.0 
0.0 7.0 14.0 
0.0 8.0 16.0 
0.0 9.0 18.0

(3)结合Java解析xml创建excel导出模板:

如果我们需要定期将数据库中的部分数据导出到excel中,那么我们可以预先创建一个excel导出时的模板,以后每次导出数据时就可以根据这个模板导出格式统一的报表了。关于这个模板的格式我们可以定义在一个xml文件中,然后用Java解析这个xml文件读取样式即可

i)模板格式的xml文件student.xml:

<?xml version="1.0" encoding="UTF-8"?>
<excel id="student" code="student" name="学生信息导入">
    <colgroup>
        <col index="A" width=‘17em‘></col>
        <col index="B" width=‘17em‘></col>
        <col index="C" width=‘17em‘></col>
        <col index="D" width=‘17em‘></col>
        <col index="E" width=‘17em‘></col>
        <col index="F" width=‘17em‘></col>        
    </colgroup>
    <title>
        <tr height="16px" rowspan="2">
            <td colspan="6" value="学生信息导入" />
        </tr>
        <tr height="14px" rowspan="1">
            <td colspan="3" value="基础信息" />
            <td colspan="3" value="扩展信息" />
        </tr>
    </title>
    <thead>
        <tr height="12px">
        	<th value="编号" />
            <th value="姓名" />
            <th value="性别" />
            <th value="年龄" />
            <th value="出生日期" />
            <th value=" 爱好" />
        </tr>
    </thead>
</excel>

(2)模板创建示例:

package cn.zifangsky.excel;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class CreateTemplate {

	public static void main(String[] args) {
		SAXReader reader = new SAXReader();
		try {
			Document document = reader.read(new File("src/cn/zifangsky/excel/student.xml"));
			Element rootElement = document.getRootElement();
			// 创建工作簿
			XSSFWorkbook workbook = new XSSFWorkbook();
			// 创建sheet
			XSSFSheet sheet = workbook.createSheet("Sheet0");
			// 获取模板名称
			String templateName = rootElement.attributeValue("name");

			int rowNum = 0; // 初始行号
			// 设置列宽
			Element colGroup = rootElement.element("colgroup");
			setColumnWidth(sheet, colGroup);

			// 设置标题
			Element title = rootElement.element("title");
			rowNum = setTitle(workbook, sheet, title, rowNum);

			// 设置表头
			Element thead = rootElement.element("thead");
			rowNum = setHead(workbook, sheet, thead, rowNum);

			// 创建Excel文件
			File POIExcelFile = new File("C:/Users/Administrator/Desktop/template.xlsx");
			POIExcelFile.createNewFile();
			OutputStream outputStream = new FileOutputStream(POIExcelFile);
			workbook.write(outputStream);

			outputStream.close();
			workbook.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 单位转换
	 */
	public static int convert(String value) {
		// 得到宽度单位
		String unit = value.replaceAll("\\d", "");
		// 去除非数字字符
		String num = value.replaceAll("\\D", "");

		int v = 0;
		if (StringUtils.isNotBlank(unit) && StringUtils.isNotBlank(num))
			if (unit.equals("em")) {
				v = Math.round(Float.valueOf(num) * 267.5F);
			} else if (unit.equals("px")) {
				v = Math.round(Float.valueOf(num) * 20F);
			}
		return v;
	}

	/**
	 * 设置列宽
	 */
	private static void setColumnWidth(XSSFSheet sheet, Element colGroup) {
		List<Element> cols = colGroup.elements();
		for (int i = 0; i < cols.size(); i++) {
			Element col = cols.get(i);

			Attribute widthAttribute = col.attribute("width");

			// 设置宽度
			sheet.setColumnWidth(i, convert(widthAttribute.getValue()));
		}
	}

	/**
	 * 设置标题相关内容
	 */
	private static int setTitle(XSSFWorkbook workbook, XSSFSheet sheet, Element title, int rowNum) {
		List<Element> trs = title.elements("tr");

		int rspan = 0; // 横跨多少行
		int cspan = 0; // 横跨多少列
		// 遍历多行标题
		for (int i = 0; i < trs.size(); i++, rowNum += rspan) {
			Element tr = trs.get(i);
			Attribute rowSpan = tr.attribute("rowspan");
			Attribute height = tr.attribute("height");
			rspan = Integer.valueOf(rowSpan.getValue());

			List<Element> tds = tr.elements("td");
			XSSFRow row = sheet.createRow(rowNum);

			// 遍历标题中的多列子标题
			for (int j = 0, colNum = 0; j < tds.size(); j++, colNum += cspan) {
				// 表格样式
				XSSFCellStyle cellStyle = workbook.createCellStyle();
				cellStyle.setAlignment(HorizontalAlignment.CENTER); // 居中

				Element td = tds.get(j);
				XSSFCell cell = row.createCell(colNum);

				Attribute colSpan = td.attribute("colspan");
				Attribute value = td.attribute("value");
				cspan = Integer.valueOf(colSpan.getValue());
				if (value != null) {
					cell.setCellValue(value.getValue());

					// 设置字体
					XSSFFont font = workbook.createFont();
					font.setFontName("宋体");
					font.setBold(true);
					font.setFontHeight((short) convert(height.getValue()));
					cellStyle.setFont(font);
					cell.setCellStyle(cellStyle);

					// 合并单元格
					sheet.addMergedRegion(new CellRangeAddress(rowNum, rowNum + rspan - 1, colNum, colNum + cspan - 1));
				}
			}
		}
		return rowNum;
	}

	/**
	 * 设置表头相关内容
	 */
	private static int setHead(XSSFWorkbook workbook, XSSFSheet sheet, Element thead, int rowNum) {
		List<Element> trs = thead.elements("tr");
		for (int i = 0; i < trs.size(); i++, rowNum++) {
			Element tr = trs.get(i);
			XSSFRow row = sheet.createRow(rowNum);
			Attribute height = tr.attribute("height");

			List<Element> ths = tr.elements("th");
			for (int j = 0; j < ths.size(); j++) {
				// 表格样式
				XSSFCellStyle cellStyle = workbook.createCellStyle();
				cellStyle.setAlignment(HorizontalAlignment.CENTER); // 居中

				Element th = ths.get(j);
				Attribute value = th.attribute("value");
				XSSFCell cell = row.createCell(j);
				if (value != null) {
					cell.setCellValue(value.getValue());

					// 设置字体
					XSSFFont font = workbook.createFont();
					font.setFontName("宋体");
					font.setFontHeight((short) convert(height.getValue()));
					cellStyle.setFont(font);
					cell.setCellStyle(cellStyle);
				}
			}
		}
		return rowNum;
	}
}

最后生成的模板文件如下:

注:我这里仅仅只是写了一个生成模板文件的测试代码,因此涉及到JDBC方面的操作就省略掉了

PS:上面图片中的水印是我个人博客的域名,因此还请管理员手下留情不要给我标为“转载文章”,谢谢!!!

时间: 2024-08-07 03:59:43

Java基础系列19:使用JXL或者POI生成和解析Excel文件的相关文章

夯实Java基础系列10:深入理解Java中的异常体系

目录 为什么要使用异常 异常基本定义 异常体系 初识异常 异常和错误 异常的处理方式 "不负责任"的throws 纠结的finally throw : JRE也使用的关键字 异常调用链 自定义异常 异常的注意事项 当finally遇上return JAVA异常常见面试题 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 - Java异常 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.c

java基础学习——19、String类

之前的Java基础系列中讨论了Java最核心的概念,特别是面向对象的基础.在Java进阶中,我将对Java基础进行补充,并转向应用层面. 大部分编程语言都能够处理字符串(String).字符串是有序的字符集合,比如"Hello World!".在Java中,字符串被存储为String类对象.调用字符串对象的方法,可以实现字符串相关的操作. String类包含在java.lang包中.这个包会在Java启动的时候自动import,所以可以当做一个内置类(built-in class).我

《Java 基础系列》初步整理

<Java 基础系列>初步整理大概有 12 篇,主要内容为.: 抽象类和接口内部类修饰符装箱拆箱注解反射泛型异常集合IO字符串其他第一篇我们来聊聊抽象类和接口. "抽象类和接口"听起来是非常普遍的东西,有些朋友会觉得:这个太基础了吧,有啥好说的,你又来糊弄我. 这里写图片描述 事实上我在面试中不仅一次被问到相关的问题: 抽象类和接口之间的区别?什么时候创建抽象类?什么时候创建接口?设计框架时该如何选择?我比较喜欢这样的问题,答案可深可浅,体现了我们对日常工作的思考. 我们什

夯实Java基础系列4:一文了解final关键字的特性、使用方法,以及实现原理

目录 final使用 final变量 final修饰基本数据类型变量和引用 final类 final关键字的知识点 final关键字的最佳实践 final的用法 关于空白final final内存分配 使用final修饰方法会提高速度和效率吗 使用final修饰变量会让变量的值不能被改变吗: 如何保证数组内部不被修改 final方法的三条规则 final 和 jvm的关系 写 final 域的重排序规则 读 final 域的重排序规则 如果 final 域是引用类型 参考文章 微信公众号 Jav

夯实Java基础系列6:一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别!

目录 抽象类介绍 为什么要用抽象类 一个抽象类小故事 一个抽象类小游戏 接口介绍 接口与类相似点: 接口与类的区别: 接口特性 抽象类和接口的区别 接口的使用: 接口最佳实践:设计模式中的工厂模式 接口与抽象类的本质区别是什么? 基本语法区别 设计思想区别 如何回答面试题:接口和抽象类的区别? 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl

夯实Java基础系列7:一文读懂Java 代码块和执行顺序

目录 Java中的构造方法 构造方法简介 构造方法实例 例 1 例 2 Java中的几种构造方法详解 普通构造方法 默认构造方法 重载构造方法 java子类构造方法调用父类构造方法 Java中的代码块简介 Java代码块使用 局部代码块 构造代码块 静态代码块 Java代码块.构造方法(包含继承关系)的执行顺序 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github

夯实Java基础系列9:深入理解Class类和Object类

目录 Java中Class类及用法 Class类原理 如何获得一个Class类对象 使用Class类的对象来生成目标类的实例 Object类 类构造器public Object(); registerNatives()方法; Clone()方法实现浅拷贝 getClass()方法 equals()方法 hashCode()方法; toString()方法 wait() notify() notifAll() finalize()方法 CLass类和Object类的关系 参考文章 微信公众号 Ja

夯实Java基础系列13:深入理解Java中的泛型

目录 泛型概述 一个栗子 特性 泛型的使用方式 泛型类 泛型接口 泛型通配符 泛型方法 泛型方法的基本用法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型方法总结 泛型上下边界 泛型常见面试题 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下Star.Fork.Watch三连哈,感谢你的

Java基础系列1:深入理解Java数据类型

Java基础系列1:深入理解Java数据类型 当初学习计算机的时候,教科书中对程序的定义是:程序=数据结构+算法,Java基础系列第一篇就聊聊Java中的数据类型. 本篇聊Java数据类型主要包括四个内容: Java基本类型 Java封装类型 自动装箱和拆箱 封装类型缓存机制 Java基本类型 Java基本类型分类.大小及表示范围 Java的基本数据类型总共有8种,包括三类:数值型,字符型,布尔型,其中 数值型: 整数类型:byte.short.int.long 浮点类型:float.doubl