package com.vci.client.utils.excel;
import java.awt.Component;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import org.apache.poi.hssf.OldExcelFormatException;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
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.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import com.vci.client.ui.exception.VCIException;
import com.vci.client.ui.swing.VCISwingUtil;
import com.vci.client.ui.swing.components.VCIJOptionPane;
/**
*
* Title: read infos from excel file or write infos into excel file.
*
*
* Description:
*
*
* Copyright: Copyright (c) 2009
*
*
* Company: VCI
*
*
* @author eddie
* @time 2009-6-15
* @version 1.0
*/
public class ExcelFileOperation {
public ExcelFileOperation() {
}
/**
* 写入Excel
* Description:
* @author: xchao
* @time 2014-10-24 下午5:51:15
* @param path 文件路径
* @param excelInfoMap 数据 key:sheetName value:String[][] 形式的数据
* @param settingMap 为每个sheet 设置的样式 key:sheetName value:ExcelCellStyleSettingCallback 形式的数据
* @return 是否写入成功
*/
public boolean writeExcelFileInfo(String path, Map excelInfoMap,
Map settingMap){
boolean isSucess = false;
if(path == null || excelInfoMap == null){
return isSucess;
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream(path);
Workbook wb = null;
boolean isEndWithXlsx = path.endsWith(".xlsx");
if(isEndWithXlsx){
SXSSFWorkbook swb = new SXSSFWorkbook(100);
swb = new SXSSFWorkbook(100);
swb.setCompressTempFiles(true);
wb = swb;
} else{
// 用 HSSFWorkbook 处理2003或以下版本EXCEL文件
wb = new HSSFWorkbook();
}
Iterator its = excelInfoMap.keySet().iterator();
while(its.hasNext()){
String sheetName = its.next();
Sheet sheet = wb.createSheet(sheetName);
String[][] excelInfos = excelInfoMap.get(sheetName);
if(excelInfos == null) continue;
ExcelCellStyleSettingCallback setting = settingMap == null ? null : settingMap.get(sheetName);
isSucess &= writeExcelInfo(wb, sheet, excelInfos, setting, isEndWithXlsx);
}
wb.write(fos);
fos.close();
isSucess = true;
} catch (Exception e) {
e.printStackTrace();
isSucess = false;
throw new RuntimeException(e);
} finally{
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return isSucess;
}
private boolean writeExcelInfo(Workbook wb, Sheet sheet, String[][] excelInfos, ExcelCellStyleSettingCallback setting, boolean isEndWithXlsx){
boolean isSucess = false;
WorkboolStyleSetting wbStyleSetting = null;
LinkedHashMap styleMap = null;
if(setting != null){
wbStyleSetting = setting.doSetWorkbookStyle(wb);
styleMap = wbStyleSetting.getStyleMap();
}
// 文本类型列样式
DataFormat fmt = wb.createDataFormat();
CellStyle textStyle = wb.createCellStyle();
textStyle.setDataFormat(fmt.getFormat("@"));
int row = excelInfos.length;
int column = -1;
for (int i = 0; i < row; i++) {
Row rowData = sheet.createRow(i);
column = excelInfos[i].length;
for (int j = 0; j < column; j++) {
Cell cell = rowData.createCell(j);
if (excelInfos[i][j] == null) {
cell.setCellValue("");
} else {
cell.setCellValue("" + excelInfos[i][j]);
}
cell.setCellType(Cell.CELL_TYPE_STRING);
if(styleMap != null && styleMap.containsKey(""+i+"*"+j+"")){
CellStyle cs = styleMap.get(""+i+"*"+j+"");
cs.setDataFormat(textStyle.getDataFormat());
cell.setCellStyle(cs);
} else{
cell.setCellStyle(textStyle);
}
}
}
// add by xchao 2013.10.28 begin
if(!isEndWithXlsx){
// 设置列的单元格类型为文本
for(int i = 0; i < 256; i++){
sheet.setDefaultColumnStyle(i, textStyle);
}
}
// add by xchao 2013.10.28 end
isSucess = true;
return isSucess;
}
public boolean writeExcelFileInfo(String path, String sheetName, String[][] excelInfos, ExcelCellStyleSettingCallback setting){
Map excelInfoMap = new LinkedHashMap();
excelInfoMap.put(sheetName, excelInfos);
Map settingMap = new LinkedHashMap();
settingMap.put(sheetName, setting);
return writeExcelFileInfo(path, excelInfoMap, settingMap);
}
/**
* write infos into a excel file. The columns of every row are not equal.
*
* @param path
* String, the file's whole path
* @param sheetName
* String, sheet description
* @param excelInfos
* String[][], the infos which will be writed into excel file
* @return
*/
public boolean writeExcelFileInfo(String path, String sheetName, String[][] excelInfos) {
return writeExcelFileInfo(path, sheetName,excelInfos, null);
}
/**
* 检查指定路径的excel文件是否是能够支持的EXCEL文件
* @param parentComponent 父容器对象
* @param path 文件完整路径
* @return
*/
public boolean isSupportExcelFormat(Component parentComponent, String path){
boolean res = false;
boolean isXls = (path.endsWith(".xls") || path.endsWith(".xlsx"));
// 如果是.xlsx格式,检查格式问题,会有卡钝现象,故简化处理
if(isXls){
return true;
}
File file = new File(path);
// 如果文件后缀是excel格式,但文件不存在时,此时返回true
if(isXls && !file.exists()) {
return true;
}
if(file.length() == 0) return true;
Workbook wb = null;
POIFSFileSystem fs = null;
try{
// XSSFWorkbook 支持OFFICE EXCEL 2007,
// 但不支持2003以下的,包含2003
wb = new XSSFWorkbook(new FileInputStream(path));
res = true;
}catch(Exception ex){
try {
// 用 HSSFWorkbook 处理2003或以下版本EXCEL文件
fs = new POIFSFileSystem(new FileInputStream(path));
wb = new HSSFWorkbook(fs);
res = true;
} catch(OldExcelFormatException e){
e.printStackTrace();
VCIJOptionPane.showError(parentComponent, "Excel文件版本错误,当前支支持 Excel 97/2000/XP/2003/2007/2010");
res = false;
} catch(IOException e){
e.printStackTrace();
if(e.getMessage().contains("Invalid header signature")){
VCIJOptionPane.showError(parentComponent, "文件类型错误,不是有效的Excel文件!");
}
res = false;
} catch(Exception e){
e.printStackTrace();
VCIJOptionPane.showError(parentComponent, "检查文件是否是有效的Excel文件时发生错误!\n" + e.getMessage());
res = false;
}
}
return res;
}
/**
* 返回Excel文件里数据(全部Sheet)
* @param path Excel 文件完整路径
* @return
* @throws VCIException
*/
public String[][][] readExcelFileInfos(String path) throws VCIException{
String[][][] res = new String[][][]{};
Workbook wb = getWorkBook(path);
if(wb == null){
return res;
}
int sheetCount = wb.getNumberOfSheets();
res = new String[sheetCount][0][0];
for(int sheetIndex = 0; sheetIndex < sheetCount; sheetIndex++){
res[sheetIndex] = readExcelFileInfo(path, sheetIndex);
}
return res;
}
/**
* 返回Excel文件里的数据(根据指定的Sheet名称)
* @param path Excel 文件完整路径
* @param sheetName Sheet 名称
* @return
* @throws VCIException
*/
public String[][] readExcelFileInfo(String path, String sheetName) throws VCIException {
String[][] res = new String[][]{};
Workbook wb = getWorkBook(path);
if(wb == null){
return res;
}
int sheetIndex = wb.getSheetIndex(sheetName);
if(sheetIndex < 0){
return res;
}
return readExcelFileInfo(path, sheetIndex);
}
/**
* 返回Excel文件里的数据(默认返回第一个Sheet里的数据)
* @param path Excel 文件完整路径
* @return
* @throws VCIException
*/
public String[][] readExcelFileInfo(String path) throws VCIException {
return readExcelFileInfo(path, 0);
}
/**
* 返回Excel文件里的数据(根据指定的Sheet索引)
* @param path Excel 文件完整路径
* @param sheetIndex Sheet索引(0 ~ SheetCount - 1)
* @return
* @throws VCIException
*/
public String[][] readExcelFileInfo(String path, int sheetIndex) throws VCIException {
String[][] excelInfos = null;
/**
* 读取逻辑&&约束
* 1、标题&抬头行不能出现任何的空数据列
* 2、标题&抬头行不能出现纯数字列
*/
// 取Sheet对象
Sheet sheet = this.getWorkbookSheet(path, sheetIndex);
if(sheet == null) return new String[0][0];
LinkedList datas = new LinkedList();
if(sheet.getLastRowNum() <= 0){
throw new VCIException(String.valueOf("99996"), new Object[]{});// 该文件只有标题&抬头行或没有数据(连标题&抬头行都没有)!
}
StringBuffer sbRowValueString = new StringBuffer();
// 取标题行有效的列数
int firstRowColumnNum = this.getFirstRowColumnNum(sheet);
for(int i = 0; i < sheet.getLastRowNum() + 1; i++){
Row row = sheet.getRow(i);
if(row == null) { // 整行都没有数据
i++;
continue;
}
sbRowValueString = new StringBuffer();
LinkedList rowValue = new LinkedList();
for (int j = 0; j < firstRowColumnNum; j++) {
Cell cell = row.getCell(j);
String cellValueString = "";
if(i == 0){// 标题行
// 移除数据列中前可在存在的"'"
String val = cell.getStringCellValue();
while(val.startsWith("'")){
val = val.substring(1);
}
cellValueString = val;
rowValue.add(val);
sbRowValueString.append(cellValueString);
}else{// 数据行
// 处理数据行中的空数据
if(cell == null){
cellValueString = "";
}else{
cellValueString = getCellValue(cell);
}
rowValue.add(cellValueString);
sbRowValueString.append(cellValueString);
}
}
// add by xchao 如果数据行的数据全部为空,则不添加
if(sbRowValueString.length() != 0){
datas.add(rowValue.toArray(new String[]{}));
}
}
excelInfos = datas.toArray(new String[][]{});
return excelInfos;
}
public static String getCellValue(Cell cell){
String cellValueString = "";
if(cell == null) return cellValueString;
int cellType = cell.getCellType();
NumberFormat numFormat = NumberFormat.getInstance(Locale.CHINA);
SimpleDateFormat sdfDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// add by xchao 2012.11.22 处理日期类型和Cell
if(cellType == Cell.CELL_TYPE_NUMERIC && HSSFDateUtil.isCellDateFormatted(cell)){
Date date = HSSFDateUtil.getJavaDate(cell.getNumericCellValue());
cellValueString = sdfDateTime.format(date);
}
else if(cellType == Cell.CELL_TYPE_BLANK){
cellValueString = "";
} else if(cellType == Cell.CELL_TYPE_BOOLEAN){
cellValueString = cell.getBooleanCellValue() ? "1" : "0";
} else if(cellType == Cell.CELL_TYPE_ERROR){
cellValueString = "";
} else if(cellType == Cell.CELL_TYPE_FORMULA){
try{
cellValueString = String.valueOf(cell.getNumericCellValue());
} catch (Exception e) {
cellValueString = cell.getRichStringCellValue().getString();
}
} else if(cellType == Cell.CELL_TYPE_NUMERIC){
// String[] dataFormatStrings = cell.getCellStyle().getDataFormatString().replace("_", "").trim().split("\\.");
// int maxFracDigits = 0;
// if(dataFormatStrings.length == 2){
// maxFracDigits = dataFormatStrings[1].length();
// numFormat.setMaximumFractionDigits(maxFracDigits);
// cellValueString = numFormat.format(cell.getNumericCellValue()).replace(",", "").trim();
// } else {
// cellValueString = cell.toString();
// }
//cell.setCellType(Cell.CELL_TYPE_STRING);
//cellValueString = cell.getStringCellValue();
DecimalFormat df = new DecimalFormat("#.#########");
cellValueString = df.format(cell.getNumericCellValue());
} else if(cellType == Cell.CELL_TYPE_STRING){
// 移除数据列中前可在存在的"'"
String val = cell.getStringCellValue();
while(val.startsWith("'")){
val = val.substring(1);
}
cellValueString = val;
}
return cellValueString;
}
/**
* 返回Sheet的标题&抬头行的实际有效的列数
* @param sheet
* @return
* @throws VCIException
*/
private int getFirstRowColumnNum(Sheet sheet) throws VCIException{
int i = 0;
Row row = sheet.getRow(i);
int rowCellNum = row.getLastCellNum();
int firstRowColumnNum = 0;
for (int j = 0; j < rowCellNum; j++) {
int columnIndex = j;
int columnIndexToShow = columnIndex + 1;
Cell cell = row.getCell(j);
int cellType = 0;
if(i == 0){// 标题行
if(cell == null){
throw new VCIException(String.valueOf("99995"), new Object[]{columnIndexToShow});// 标题&抬头行中的第{0}列的不能为空!
}
cellType = cell.getCellType();
if(cellType == Cell.CELL_TYPE_BLANK){
throw new VCIException(String.valueOf("99995"), new Object[]{columnIndexToShow});// 标题&抬头行中的第{0}列的不能为空!
}
if(cellType == Cell.CELL_TYPE_NUMERIC || cellType == Cell.CELL_TYPE_NUMERIC){
throw new VCIException(String.valueOf("99994"), new Object[]{columnIndexToShow});// 标题&抬头行中的第{0}列不能是纯数字!
}
// 计算标题行有效列数
firstRowColumnNum += 1;
}
}
return firstRowColumnNum;
}
/**
* 批回指定文件的Sheet
* @param path excel文件完整路径
* @param sheetIndex Sheet 索引(从0 ~ SheetCount-1)
* @return
* @throws VCIException
*/
private Sheet getWorkbookSheet(String path, int sheetIndex) throws VCIException{
Workbook wb = getWorkBook(path);
if(wb == null) return null;
int sheetCount = wb.getNumberOfSheets();
if(sheetIndex < 0 || sheetIndex >= sheetCount) return null;
return wb.getSheetAt(sheetIndex);
}
private Workbook getWorkBook(String path) throws VCIException{
Workbook wb = null;
POIFSFileSystem fs = null;
try{
// XSSFWorkbook 支持OFFICE EXCEL 2007,
// 但不支持2003以下的,包含2003
wb = new XSSFWorkbook(new FileInputStream(path));
}catch(Exception ex){
try {
// 用 HSSFWorkbook 处理2003或以下版本EXCEL文件
fs = new POIFSFileSystem(new FileInputStream(path));
wb = new HSSFWorkbook(fs);
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new VCIException("99999", new String[]{path});
} catch (IOException e) {
e.printStackTrace();
throw new VCIException("99998", new String[]{path});
} catch(Exception e){
e.printStackTrace();
throw new VCIException("99997", new String[]{path, e.getMessage()});
}
}
return wb;
}
public static void main(String[] args) throws VCIException{
String path = "E:/";
String name = "test.xlsx";
String[][] datas = new ExcelFileOperation().readExcelFileInfo(path + name);
for(String[] row : datas){
for(String val : row){
System.out.print(val + "\t");
}
System.out.println("");
}
// writeTest();
// readTest();
}
private static void readTest() throws VCIException{
String path = VCISwingUtil.getExcelFileURL(null, false, "");
System.out.println("readTest1:");
readTest1(path);
System.out.println("readTest2:");
readTest2(path);
System.out.println("readTest3:");
readTest3(path);
System.out.println("readTest4:");
readTest4(path);
}
private static void readTest1(String path) throws VCIException{
out(new ExcelFileOperation().readExcelFileInfo(path));
}
private static void readTest2(String path) throws VCIException{
if(path == null) return;
out(new ExcelFileOperation().readExcelFileInfo(path, 0));
out(new ExcelFileOperation().readExcelFileInfo(path, 1));
out(new ExcelFileOperation().readExcelFileInfo(path, 2));
out(new ExcelFileOperation().readExcelFileInfo(path, 3));
}
private static void readTest3(String path) throws VCIException{
if(path == null) return;
out(new ExcelFileOperation().readExcelFileInfo(path, "Sheet1"));
out(new ExcelFileOperation().readExcelFileInfo(path, "Sheet2"));
out(new ExcelFileOperation().readExcelFileInfo(path, "Sheet3"));
out(new ExcelFileOperation().readExcelFileInfo(path, "Sheet4"));
}
private static void readTest4(String path) throws VCIException{
if(path == null) return;
out(new ExcelFileOperation().readExcelFileInfos(path));
}
private static void out(String[][][] datas){
for(String[][] data : datas){
out(data);
}
}
private static void out(String[][] datas){
for(String[] row : datas){
for(String cell : row){
System.out.print(cell + "\t");
}
System.out.print("\n");
}
}
private static void writeTest(){
ExcelFileOperation efo = new ExcelFileOperation();
boolean isRead = false;
File file = null;
String filePath = VCISwingUtil.getExcelFileURL(null, !isRead, "");
if(filePath != null){
file = new File(filePath);
}
if(file == null){
System.exit(0);
}
LinkedList list = new LinkedList();
for(int i = 0; i < 100; i++){
LinkedList row = new LinkedList();
for(int j = 0; j < 52; j++){
row.add(String.valueOf(j));
}
list.add(row.toArray(new String[]{}));
}
String[][] excelInfos = {{"a","b","c"},{"123","456","789"}};
excelInfos = list.toArray(new String[][]{});
ExcelCellStyleSettingCallback setting = new ExcelCellStyleSettingCallback() {
public WorkboolStyleSetting doSetWorkbookStyle(final Workbook workbook) {
WorkboolStyleSetting setting = new WorkboolStyleSetting() {
public LinkedHashMap getStyleMap() {
LinkedHashMap styleMap = new LinkedHashMap();
org.apache.poi.ss.usermodel.CellStyle style = workbook.createCellStyle();
org.apache.poi.ss.usermodel.Font font = (org.apache.poi.ss.usermodel.Font)workbook.createFont();
font.setColor(HSSFFont.COLOR_RED);
style.setFont(font);
styleMap.put("0*0", style);
return styleMap;
}
};
return setting;
}
};
Map excelInfoMap = new LinkedHashMap();
excelInfoMap.put("sheet1", excelInfos);
excelInfoMap.put("sheet2", excelInfos);
excelInfoMap.put("sheet3", excelInfos);
Map settingMap = new HashMap();
settingMap.put("sheet1", setting);
efo.writeExcelFileInfo(file.getAbsolutePath(), excelInfoMap, settingMap);
}
}