原文地址:http://www.journaldev.com/2562/java-readwrite-excel-file-using-apache-poi-api.
有时候我们需要从Excel文件中读取数据,或者我们为了商务或者财政的目的生成Excel格式的报表.Java没有对操作Excel文件提供内在的支持,所以我们需要寻找开源的APIs.当我开始寻找操作Excel的APIs时候,大部分人建议使用JExcel或者Apache POI.
在深入研究后,我发现由于以下主要原因Apache POI是正确的选择.还有些关于高级特性的原因,但是我们不深入太多细节.
1)Apache基金的支持.
2)JExcel不支持xlsx格式而POI既支持xls格式又支持xlsx格式.
3)Apache POI是基于流的处理,因此更适合大文件和要求更少的内存.
Apache POI对处理Excel文件提供了强大的支持,并且能处理xls和xlsx格式的电子表格.
关于Apache POI一些重要的地方:
1)Apache POI包含适合Excel97-2007(.xls文件)的HSSF实现.
2)Apache POI XSSF实现用来处理Excel2007文件(.xlsx).
3)Apache POI HSSF和XSSF提供了读/写/修改Excel表格的机制.
4)Apache POI提供了XSSF的一个扩展SXSSF用来处理非常大的Excel工作单元.SXSSF API需要更少的内存,因此当处理非常大的电子表格同时堆内存又有限时,很合适使用.
5)有两种模式可供选择--事件模式和用户模式.事件模式要求更少的内存,因为用tokens来读取Excel并处理.用户模式更加面向对象并且容易使用,因此在我们的示例中使用用户 模式.
6)Apache POI为额外的Excel特性提供了强大支持,例如处理公式,创建单元格样式--颜色,边框,字体,头部,脚部,数据验证,图像,超链接等.
Apache POI的Maven依赖
[java] view plaincopyprint?
- <span style="font-size:14px;"><dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi</artifactId>
- <version>3.10-FINAL</version>
- </dependency>
- <dependency>
- <groupId>org.apache.poi</groupId>
- <artifactId>poi-ooxml</artifactId>
- <version>3.10-FINAL</version>
- </dependency></span>
Apache POI的当前版本是3.10-FINAL.如果你使用单独的java应用,添加jars根据下面的图片.
读取Excel文件
假设我们有一个叫Sample.xlsx的Excel文件,里面有两个sheet并且下面图片中的数据.我们想要读取这个Excel文件并且创建Countries list.sheet1有些额外的数据,当我们解析时会忽略它.
我们的国家(Country)java bean如下:
Country.java
[java] view plaincopyprint?
- package com.journaldev.excel.read;
-
- public class Country {
-
- private String name;
- private String shortCode;
-
- public Country(String n, String c){
- this.name=n;
- this.shortCode=c;
- }
-
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getShortCode() {
- return shortCode;
- }
- public void setShortCode(String shortCode) {
- this.shortCode = shortCode;
- }
-
- @Override
- public String toString(){
- return name + "::" + shortCode;
- }
-
- }
读取Excel文件并创建Countries list代码如下:
ReadExcelFileToList.java
[java] view plaincopyprint?
- package com.journaldev.excel.read;
-
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
-
- import org.apache.poi.hssf.usermodel.HSSFWorkbook;
- import org.apache.poi.ss.usermodel.Cell;
- import org.apache.poi.ss.usermodel.Row;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.usermodel.Workbook;
- import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
- public class ReadExcelFileToList {
-
- public static List<Country> readExcelData(String fileName) {
- List<Country> countriesList = new ArrayList<Country>();
-
- try {
-
- FileInputStream fis = new FileInputStream(fileName);
-
-
- Workbook workbook = null;
- if(fileName.toLowerCase().endsWith("xlsx")){
- workbook = new XSSFWorkbook(fis);
- }else if(fileName.toLowerCase().endsWith("xls")){
- workbook = new HSSFWorkbook(fis);
- }
-
-
- int numberOfSheets = workbook.getNumberOfSheets();
-
-
- for(int i=0; i < numberOfSheets; i++){
-
-
- Sheet sheet = workbook.getSheetAt(i);
-
-
- Iterator<Row> rowIterator = sheet.iterator();
- while (rowIterator.hasNext())
- {
- String name = "";
- String shortCode = "";
-
-
- Row row = rowIterator.next();
-
-
- Iterator<Cell> cellIterator = row.cellIterator();
-
- while (cellIterator.hasNext())
- {
-
- Cell cell = cellIterator.next();
-
-
- switch(cell.getCellType()){
- case Cell.CELL_TYPE_STRING:
- if(shortCode.equalsIgnoreCase("")){
- shortCode = cell.getStringCellValue().trim();
- }else if(name.equalsIgnoreCase("")){
-
- name = cell.getStringCellValue().trim();
- }else{
-
- System.out.println("Random data::"+cell.getStringCellValue());
- }
- break;
- case Cell.CELL_TYPE_NUMERIC:
- System.out.println("Random data::"+cell.getNumericCellValue());
- }
- }
- Country c = new Country(name, shortCode);
- countriesList.add(c);
- }
-
-
- }
-
-
- fis.close();
-
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- return countriesList;
- }
-
- public static void main(String args[]){
- List<Country> list = readExcelData("Sample.xlsx");
- System.out.println("Country List\n"+list);
- }
-
- }
这个程序很容易明白,主要步骤如下:
1)根据文件类型(.xls与.xlsx)创建Workbook实例,xlsx用XSSFWorkbook,xls用HSSFWorkbook.我们可以基于文件名字使用工 厂模式创建一个包装类来创建Workbook实例.
2)使用Workbook getNumberOfSheets()来获取sheet的数量,然后循环解析每一个sheet.使用getSheetAt(int i)方法获取 Sheet实例.
3)获取Row和Cell迭代器来获取每一个Cell对象.Apache POI在这里使用了迭代器模式.
4)使用switch-case根据Cell的类型来处理它.
现在我们运行上面的程序,在控制台产生如下的输出:
[java] view plaincopyprint?
- Random data::1.0
- Random data::2.0
- Random data::3.0
- Random data::4.0
- Country List
- [India::IND, Afghanistan::AFG, United States of America::USA, Anguilla::AIA,
- Denmark ::DNK, Dominican Republic ::DOM, Algeria ::DZA, Ecuador ::ECU]
写入Excel文件
除了我们首先创建Workbook,然后设置sheets,rows,cells的值并且使用FileOutputStream把Workbook写入文件外,与读取Excel的操作相似.我们把从上面的方法读取countries list写入到另一个文件作一个例子:
WriteListToExcelFile.java
[java] view plaincopyprint?
- package com.journaldev.excel.read;
-
- import java.io.FileOutputStream;
- import java.util.Iterator;
- import java.util.List;
-
- import org.apache.poi.hssf.usermodel.HSSFWorkbook;
- import org.apache.poi.ss.usermodel.Cell;
- import org.apache.poi.ss.usermodel.Row;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.usermodel.Workbook;
- import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
- public class WriteListToExcelFile {
-
- public static void writeCountryListToFile(String fileName, List<Country> countryList) throws Exception{
- Workbook workbook = null;
-
- if(fileName.endsWith("xlsx")){
- workbook = new XSSFWorkbook();
- }else if(fileName.endsWith("xls")){
- workbook = new HSSFWorkbook();
- }else{
- throw new Exception("invalid file name, should be xls or xlsx");
- }
-
- Sheet sheet = workbook.createSheet("Countries");
-
- Iterator<Country> iterator = countryList.iterator();
-
- int rowIndex = 0;
- while(iterator.hasNext()){
- Country country = iterator.next();
- Row row = sheet.createRow(rowIndex++);
- Cell cell0 = row.createCell(0);
- cell0.setCellValue(country.getName());
- Cell cell1 = row.createCell(1);
- cell1.setCellValue(country.getShortCode());
- }
-
-
- FileOutputStream fos = new FileOutputStream(fileName);
- workbook.write(fos);
- fos.close();
- System.out.println(fileName + " written successfully");
- }
-
- public static void main(String args[]) throws Exception{
- List<Country> list = ReadExcelFileToList.readExcelData("Sample.xlsx");
- WriteListToExcelFile.writeCountryListToFile("Countries.xls", list);
- }
- }
当我们执行上面的程序后,这个Excel文件被创建了,如下图:
读取Excel公式
有时候我们需要出来带有公司的复杂Excel文件.让我们来看一个关于读取一个有值的cell中的公式的例子:
ReadExcelFormula.java
[java] view plaincopyprint?
- package com.journaldev.excel.read;
-
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.util.Iterator;
-
- import org.apache.poi.ss.usermodel.Cell;
- import org.apache.poi.ss.usermodel.Row;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.usermodel.Workbook;
- import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
- public class ReadExcelFormula {
-
- public static void readExcelFormula(String fileName) throws IOException{
-
- FileInputStream fis = new FileInputStream(fileName);
-
-
- Workbook workbook = new XSSFWorkbook(fis);
- Sheet sheet = workbook.getSheetAt(0);
- Iterator<Row> rowIterator = sheet.iterator();
- while (rowIterator.hasNext())
- {
- Row row = rowIterator.next();
- Iterator<Cell> cellIterator = row.cellIterator();
-
- while (cellIterator.hasNext())
- {
- Cell cell = cellIterator.next();
- switch(cell.getCellType()){
- case Cell.CELL_TYPE_NUMERIC:
- System.out.println(cell.getNumericCellValue());
- break;
- case Cell.CELL_TYPE_FORMULA:
- System.out.println("Cell Formula="+cell.getCellFormula());
- System.out.println("Cell Formula Result Type="+cell.getCachedFormulaResultType());
- if(cell.getCachedFormulaResultType() == Cell.CELL_TYPE_NUMERIC){
- System.out.println("Formula Value="+cell.getNumericCellValue());
- }
- }
- }
- }
- }
-
- public static void main(String args[]) throws IOException {
- readExcelFormula("FormulaMultiply.xlsx");
- }
- }
当我们执行上面的程序后,我们得到下面的输出:
[java] view plaincopyprint?
- 1.0
- 2.0
- 3.0
- 4.0
- Cell Formula=A1*A2*A3*A4
- Cell Formula Result Type=0
- Formula Value=24.0
写入Excel公式
有时候,我们需要做一些计算然后把值写入cell.我们可以使用Excel公司来做这些计算,这样会更加精确,因为这些值会随着计算的值改变而改变.让我们来看一个关于写入一个带有公式的Excel的例子:
WriteExcelWithFormula.java
[java] view plaincopyprint?
- package com.journaldev.excel.read;
-
- import java.io.FileOutputStream;
- import java.io.IOException;
-
- import org.apache.poi.ss.usermodel.Row;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.usermodel.Workbook;
- import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
- public class WriteExcelWithFormula {
-
- public static void writeExcelWithFormula(String fileName) throws IOException{
- Workbook workbook = new XSSFWorkbook();
- Sheet sheet = workbook.createSheet("Numbers");
- Row row = sheet.createRow(0);
- row.createCell(0).setCellValue(10);
- row.createCell(1).setCellValue(20);
- row.createCell(2).setCellValue(30);
-
- row.createCell(3).setCellFormula("A1*B1*C1");
-
-
- FileOutputStream fos = new FileOutputStream(fileName);
- workbook.write(fos);
- fos.close();
- System.out.println(fileName + " written successfully");
- }
-
- public static void main(String[] args) throws IOException {
- writeExcelWithFormula("Formulas.xlsx");
- }
- }
当我们执行上面的程序后,Excel被创建了,如下图:
这就是所有Apache POI处理Excel文件的内容.查看POI源代码可以学习它的更多特性.