Java操作Microsoft Office用到的专业的类库为Apache POI。Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。此篇文章只介绍对Excel(.xls/.xlsx)的操作,包括:创建、查询、修改、删除、更新等。


1 Excel的创建

Excel的创建可以分为2007版本及其以上(.xlsx)和2007版本一下的(.xls),其完整的Excel创建代码如下:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import javax.swing.JOptionPane;

import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import org.apache.poi.ss.usermodel.Row;


/**
 * 创建Excel的操作
 * @author liguohui
 *
 */
public class ExcelCreater {
	private String filePath = null; // Excel文件的路径(包含文件名)
	private List<String> definition = null;
	
	/**
	 * 构造方法
	 * @param filePath 要创建的Excel文件的路径(包含文件名)
	 * @param definition 该表格的定义。(即表格第一行的内容)
	 */
	public ExcelCreater(String filePath, List<String> definition) {
		this.filePath = filePath;
		this.definition = definition;
	}
	
	/**
	 * 创建
	 * @return
	 */
	public Workbook create() {
		File file = new File(filePath);
		if(file.exists()) { //文件已经存在
			int op = JOptionPane.showConfirmDialog(null, "文件:" + filePath + " 已经存在,是否覆盖?", "提示信息", 0);
			if(op == 0) { //选择了:是
				file.delete(); //必须先删除,要不然下面就是对Excel表格进行append,而不是覆盖添加
			} else { //选择了:否或直接点X
				return null;
			}
		}
		Workbook workbook = null;
		if(filePath.endsWith(".xlsx") || filePath.endsWith(".XLSX")) { //2007版本及以上
			workbook = new XSSFWorkbook();
		} else if(filePath.endsWith(".xls") || filePath.endsWith(".XLS")){ //97-03版本
			workbook = new HSSFWorkbook();
		} else {
			throw new RuntimeException("文件格式错误");
		}
		
		Sheet sheet = workbook.createSheet(); //创建一个Sheet
		
		if(definition != null && definition.size() > 0) {
			//添加表格的定义,即:写第一行
			Row row = sheet.createRow(0);
			Cell cell;
			for(int i=0; i<definition.size(); i++) {
				cell = row.createCell(i);
				cell.setCellValue(definition.get(i));
			}
		}
		
		writeToFile(workbook);
		return workbook;
	}
	
	/**
	 * 写入到硬盘
	 */
	private synchronized void writeToFile(Workbook workbook) {
		FileOutputStream fOut = null;
		try {
			File f = new File(filePath);
			if(!f.getParentFile().exists()) {
				f.getParentFile().mkdirs();
			}
			fOut = new FileOutputStream(filePath);
			workbook.write(fOut); // 把相应的Excel 工作簿存盘
			fOut.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				fOut.close(); // 操作结束,关闭文件
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}



测试代码如下:

public void testCreateExcel() {
	List<String> defination = new ArrayList<String>();
	defination.add("id号");
	defination.add("名称");
	ExcelCreater ec = new ExcelCreater("F:\\dd.xlsx", defination);
	ec.create();
}



运行结果如下:

OFD java实现 java office_Office




2 Excel的操作(查询、修改、删除、更新)

2.1  插入

/**
 * 插入一行到指定的位置,该行下面的所有行向下移动一个
 * @param rowIndex 带插入的行(Excel表中,行是从0起算的,但该值不能为0,因为:不能插入在第0行,因为第0行为用来定义字段的!)
 * @param objs 待插入的值
 */
public synchronized void insert(int rowIndex, String[] objs) {
	if(rowIndex == 0) {
		throw new IllegalArgumentException("不能插入在第0行,因为第0行为用来定义字段的!");
	}
	if(rowIndex > sheet.getLastRowNum() + 1) {
		throw new IllegalArgumentException("最多只能插入在最后一行的后面,不能再往后插入了");
	}
	int referRowIndex = -1; //参考行的行号。
	if(sheet.getPhysicalNumberOfRows() <= 1) { //原始的表格里面没有值
		referRowIndex = rowIndex - 1;
	} else {
		referRowIndex = rowIndex - 1;
		if(rowIndex == sheet.getLastRowNum() + 1) { //是插入最后一行
			//什么都不做
		} else {
			sheet.shiftRows(rowIndex, sheet.getLastRowNum(), 1, true, false); //下移动一位
		}
	}
	Row targetRow = sheet.createRow(rowIndex);
	Row referRow = sheet.getRow(referRowIndex); // 参考行
	Cell targetCell, referCell;

	for (int i = 0; i < objs.length; i++) {
		targetCell = targetRow.createCell(i);
		referCell = referRow.getCell(i);

		targetCell.setCellStyle(referCell.getCellStyle());
		targetCell.setCellType(referCell.getCellType());

		targetCell.setCellValue(objs[i]);// 设置值
	}

	writeToFile();
}




2.2 更新

public synchronized void update(int rowIndex, String[] objs) {
	Row row = sheet.getRow(rowIndex);
	for(int i=0; i<objs.length; i++) {
		row.getCell(i).setCellValue(objs[i]);
	}
	writeToFile();
}




2.3 删除

/**
 * 删除一行数据(Excel表中,行是从0起算的)
 * @param rowIndex 要删除的行
 */
public synchronized void delete(int rowIndex) {
	if(rowIndex == sheet.getLastRowNum()) { //删除的是最后一行
		sheet.removeRow(sheet.getRow(sheet.getLastRowNum()));
	} else { //删除的不是最后一行
		sheet.shiftRows(rowIndex + 1, sheet.getLastRowNum(), -1, true, false);
		sheet.removeRow(sheet.getRow(sheet.getLastRowNum() + 1));
	}
	writeToFile();
}



2.4 读取

/**
 * 读取Excel中的【所有】二维表数据
 * 
 * @throws IOException
 */
public synchronized String[][] read() throws IOException {
	String[][] objs = new String[sheet.getPhysicalNumberOfRows()][];
	
	Row row = sheet.getRow(sheet.getFirstRowNum());
	int firstCellNum = row.getFirstCellNum();
	int lastCellNum = row.getLastCellNum();
	int r = 0, c = 0;
	Cell cell = null;
	for(int i=sheet.getFirstRowNum(); i<=sheet.getLastRowNum(); i++) {
		row = sheet.getRow(i);
		if(row == null) continue;
		objs[r] = new String[lastCellNum - firstCellNum];
		for(int j=firstCellNum; j<lastCellNum; j++) {
			cell = row.getCell(j);
			objs[r][c] = (cell == null ? null : cell.toString());
			c++;
		}
		r++;
		c = 0;
	}
	return objs;
}



其完整的Excel代码如下:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
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.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFCell;

import cn.edu.njnu.pm.dao.Blackboard;
import cn.edu.njnu.pm.dao.PMP;

/**
 * Excel的CRUD操作,但没有Excel文件的创建的操作,其创建操作专门放在ExcelCreater类里
 * 
 * @author liguohui
 * @version 2013/03/14
 */
public class ExcelEditor {
    private String filePath = null; // Excel文件的路径(包含文件名)
//    private int sheetIndex = -1; // 要读取的sheet的序号

    Workbook workbook = null;
    Sheet sheet = null;

    /**
     * 构造函数。操作了该构造函数后,表格里面的所有项都会设置为String类型
     * 
     * @param filePath
     *            Excel文件的路径(包含文件名)
     * @param sheetIndex
     *            要读取的sheet的序号
     */
    public ExcelEditor(String filePath, int sheetIndex) {
        this.filePath = filePath;
//        this.sheetIndex = sheetIndex;

        try {
            InputStream inp = new FileInputStream(filePath);
            workbook = WorkbookFactory.create(inp);
            sheet = workbook.getSheetAt(sheetIndex);
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        //将所有的都设为String类型,不管事数字形式的还是日期形式的
        Row row = sheet.getRow(sheet.getFirstRowNum());
        Cell cell = null;
        for(int i=sheet.getFirstRowNum(); i<=sheet.getLastRowNum(); i++) {
            row = sheet.getRow(i);
            if(row == null) continue;
            for(int j=row.getFirstCellNum(); j<row.getLastCellNum(); j++) {
                cell = row.getCell(j);
                if(cell != null) 
                    cell.setCellType(XSSFCell.CELL_TYPE_STRING);
            }
        }
        
        writeToFile();
    }

    /**
     * 获取每一列的宽度
     * 
     * @return 每一列的宽度
     */
    public int[] getColumnWidths() {
        int[] widths = new int[sheet.getRow(0).getPhysicalNumberOfCells()];
        for (int i = 0; i < widths.length; i++) {
            widths[i] = sheet.getColumnWidth(i);
        }
        return widths;
    }
    
    /**
     * 在表格中添加一行数据到表格的最后
     * @param objs
     */
    public synchronized void add(String[] objs) {
        insert(sheet.getLastRowNum() + 1, objs);
    }

    /**
     * 插入一行到指定的位置,该行下面的所有行向下移动一个
     * @param rowIndex 带插入的行(Excel表中,行是从0起算的,但该值不能为0,因为:不能插入在第0行,因为第0行为用来定义字段的!)
     * @param objs 待插入的值
     */
    public synchronized void insert(int rowIndex, String[] objs) {
        if(rowIndex == 0) {
            throw new IllegalArgumentException("不能插入在第0行,因为第0行为用来定义字段的!");
        }
        if(rowIndex > sheet.getLastRowNum() + 1) {
            throw new IllegalArgumentException("最多只能插入在最后一行的后面,不能再往后插入了");
        }
        int referRowIndex = -1; //参考行的行号。
        if(sheet.getPhysicalNumberOfRows() <= 1) { //原始的表格里面没有值
            referRowIndex = rowIndex - 1;
        } else {
            referRowIndex = rowIndex - 1;
            if(rowIndex == sheet.getLastRowNum() + 1) { //是插入最后一行
                //什么都不做
            } else {
                sheet.shiftRows(rowIndex, sheet.getLastRowNum(), 1, true, false); //下移动一位
            }
        }
        Row targetRow = sheet.createRow(rowIndex);
        Row referRow = sheet.getRow(referRowIndex); // 参考行
        Cell targetCell, referCell;

        for (int i = 0; i < objs.length; i++) {
            targetCell = targetRow.createCell(i);
            referCell = referRow.getCell(i);

            targetCell.setCellStyle(referCell.getCellStyle());
            targetCell.setCellType(referCell.getCellType());

            targetCell.setCellValue(objs[i]);// 设置值
        }

        writeToFile();
    }

    /**
     * 更新指定的一行
     * @param rowIndex 待更行的行(Excel表中,行是从0起算的)
     * @param objs 更新的数据
     */
    public synchronized void update(int rowIndex, String[] objs) {
        Row row = sheet.getRow(rowIndex);
        for(int i=0; i<objs.length; i++) {
            row.getCell(i).setCellValue(objs[i]);
        }
        writeToFile();
    }

    
    /**
     * 删除一行数据(Excel表中,行是从0起算的)
     * @param rowIndex 要删除的行
     */
    public synchronized void delete(int rowIndex) {
        if(rowIndex == sheet.getLastRowNum()) { //删除的是最后一行
            sheet.removeRow(sheet.getRow(sheet.getLastRowNum()));
        } else { //删除的不是最后一行
            sheet.shiftRows(rowIndex + 1, sheet.getLastRowNum(), -1, true, false);
            sheet.removeRow(sheet.getRow(sheet.getLastRowNum() + 1));
        }
        writeToFile();
    }
    
    /**
     * 更新列表宽度,自动调整的适合的宽度
     */
    public synchronized void autoSizeColumns() {
        Row firstRow = sheet.getRow(sheet.getFirstRowNum());
        for(int i=firstRow.getFirstCellNum(); i<firstRow.getLastCellNum(); i++) {
            sheet.autoSizeColumn(i);
        }
        
        writeToFile();
    }

    /**
     * 读取Excel中的【所有】二维表数据
     * 
     * @throws IOException
     */
    public synchronized String[][] read() throws IOException {
        String[][] objs = new String[sheet.getPhysicalNumberOfRows()][];
        
        Row row = sheet.getRow(sheet.getFirstRowNum());
        int firstCellNum = row.getFirstCellNum();
        int lastCellNum = row.getLastCellNum();
        int r = 0, c = 0;
        Cell cell = null;
        for(int i=sheet.getFirstRowNum(); i<=sheet.getLastRowNum(); i++) {
            row = sheet.getRow(i);
            if(row == null) continue;
            objs[r] = new String[lastCellNum - firstCellNum];
            for(int j=firstCellNum; j<lastCellNum; j++) {
                cell = row.getCell(j);
                objs[r][c] = (cell == null ? null : cell.toString());
                c++;
            }
            r++;
            c = 0;
        }
        return objs;
    }
    
    /**
     * 更新完成后,写入到硬盘
     */
    private synchronized void writeToFile() {
        FileOutputStream fOut = null;
        try {
            fOut = new FileOutputStream(filePath);
            workbook.write(fOut); // 把相应的Excel 工作簿存盘
            fOut.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fOut.close(); // 操作结束,关闭文件
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 根据传入的值找到其所在的列
     * @param name
     * @return 列的序号,从0起算
     */
    public int columnIndex(String name) {
        Row row;
        Cell cell;
        for(int i=sheet.getFirstRowNum(); i<=sheet.getLastRowNum(); i++) {
            row = sheet.getRow(i);
            for(int j=row.getFirstCellNum(); j<row.getLastCellNum(); j++) {
                cell = row.getCell(j);
                if(cell.getStringCellValue().equals(name)) {
                    return j;
                }
            }
        }
        return -1;
    }
}