最近,做了一个项目,其中一个主要的环节就是处理excel文件,之前选择使用jxl处理,后来发现不好,所以选用了poi处理,虽然还有一些不尽人意,但已经很好了。
困难之处:
1.如果选择迭代期处理单元格,可能会把空单元格直接干掉,有可能造成串列,如果你的需求不用理会串列的情况,而只是需要内容,那么无所谓,但是,如果你需要列对应关系不变的话,问题就大了
2.合并单元格拆分,这个拆分还是不太好处理的,你得考虑这个是不是合并单元格,如果是,怎么拆开,因为poi默认不处理的话,只把内容赋给第一个单元格,其他的为空,如果这样的话,就不太人性化
3.单元格存在换行,tab,空格,如果出现这些,怎么处理,而且换行还有两种形式,\n和\r
4.单元格格式问题,我在网上查,有很多种格式,但是我这个程序,只处理了其中几个,并没有全处理,因为网上那些我尝试的时候,发现并不好用,没有办法处理
5.excel文件有03版和07版,怎么兼容
大致问题差不多就这么多,也是网上没啥有用资料可用的问题
项目环境搭建就是使用maven管理工具,引入poi依赖,这个我就不多说了
我对上面问题的解决思路就是:(和上面的问题是一一对应关系,望各位观众老爷多注意)
1.我不是用迭代期来遍历单元格,而是使用传统的遍历方式,for (int aa = 0; aa <= endRow; aa++)这种遍历单元格,这样就可以把所有的单元格取出来,不管他是不是空的
2.先把这个excel文件所有的合并单元格放到一个list中保存,然后开始遍历单元格,每遍历一个单元格判断一下是否属于合并单元格,如果是,把合并单元格内容赋值给当前单元格(这个是必须设置的,不设置,就为空)
3.单元格存在的这些符号,我会把他替换成指定的字符串,以便于后面区分
4.格式问题,这个看代码
5.同上
下面开始我们最关心的环节,也就是上代码环节
a.
public static String getContent01(String filePath) {
StringBuffer sb = new StringBuffer();
if (new File(filePath).length() == 0) {
return null;
}
boolean isE2007 = false; // 判断是否是excel2007格式
if (filePath.endsWith("xlsx")) {
isE2007 = true;
}
try {
InputStream input = new FileInputStream(filePath); // 建立输入流
Workbook wb = null;
int sheets = 0;
// 根据文件格式(2003或者2007)来初始化
if (isE2007) {
wb = new XSSFWorkbook(input);
} else {
wb = new HSSFWorkbook(input);
}
sheets = wb.getNumberOfSheets();
for (int a = 0; a < sheets; a++) {
// 获取Sheet表
Sheet sheet = wb.getSheetAt(a);
// 获得合并单元格加入list中
List<CellRangeAddress> list = getCombineCell(sheet);
// 首尾两行行数
int firstRow = sheet.getFirstRowNum();
int endRow = sheet.getLastRowNum();
for (int aa = 0; aa <= endRow; aa++) {
Row row = sheet.getRow(aa);
if (row != null) {
int endCell = row.getLastCellNum();
for (int bb = 0; bb < endCell; bb++) {
boolean trueOrFalse = false;
Cell cell = row.getCell(bb);
boolean flag = false;
if (cell != null) {
// 判断是否为合并单元格
flag = isCombineCell(list, cell, sheet);
}
// System.out.println(flag);
if (flag) {
// 如果为合并单元格,将设置单元格内容
trueOrFalse = setCellValue(list, cell, sheet);
}
if (cell == null || cell.getCellType() == Cell.CELL_TYPE_BLANK) {
sb.append("\t");
} else {
String cellValue = setCellStyle(cell);
sb.append(cellValue).append("\t");
}
}
} else {
continue;
}
sb.append("\n");
}
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
b.将所有的合并单元格放到list中
/**
* 合并单元格处理--加入list
*
* @param sheet
* @return
*/
public static List<CellRangeAddress> getCombineCell(Sheet sheet) {
List<CellRangeAddress> list = new ArrayList<>();
// 获得一个 sheet 中合并单元格的数量
int sheetmergerCount = sheet.getNumMergedRegions();
// 遍历合并单元格
for (int i = 0; i < sheetmergerCount; i++) {
// 获得合并单元格加入list中
CellRangeAddress ca = sheet.getMergedRegion(i);
list.add(ca);
}
return list;
}
c.判断单元格是否为合并单元格
/**
* 判断单元格是否为合并单元格
*
* @param listCombineCell
* 存放合并单元格的list
* @param cell
* 需要判断的单元格
* @param sheet
* sheet
* @return
*/
public static Boolean isCombineCell(List<CellRangeAddress> listCombineCell, Cell cell, Sheet sheet) {
int firstC = 0;
int lastC = 0;
int firstR = 0;
int lastR = 0;
for (CellRangeAddress ca : listCombineCell) {
// 获得合并单元格的起始行, 结束行, 起始列, 结束列
firstC = ca.getFirstColumn();
lastC = ca.getLastColumn();
firstR = ca.getFirstRow();
lastR = ca.getLastRow();
if (cell.getColumnIndex() <= lastC && cell.getColumnIndex() >= firstC) {
if (cell.getRowIndex() <= lastR && cell.getRowIndex() >= firstR) {
return true;
}
}
}
return false;
}
d.得到合并单元格首行首列的值,并设置给所有合并单元格
/**
* 得到合并单元格首行首列的值,并设置给所有合并单元格
*
* @param listCombineCell
* @param cell
* @param sheet
* @return
*/
public static boolean setCellValue(List<CellRangeAddress> listCombineCell, Cell cell, Sheet sheet) {
int firstC = 0;
int lastC = 0;
int firstR = 0;
int lastR = 0;
for (CellRangeAddress ca : listCombineCell) {
// 获得合并单元格的起始行, 结束行, 起始列, 结束列
firstC = ca.getFirstColumn();
lastC = ca.getLastColumn();
firstR = ca.getFirstRow();
lastR = ca.getLastRow();
if (cell.getColumnIndex() <= lastC && cell.getColumnIndex() >= firstC) {
if (cell.getRowIndex() <= lastR && cell.getRowIndex() >= firstR) {
Row row = sheet.getRow(firstR);
Cell cell_ = row.getCell(firstC);
String cellValue = "";
if (cell_.getCellType() == Cell.CELL_TYPE_NUMERIC) {
DecimalFormat df = new DecimalFormat("#");
cellValue = df.format(cell_.getNumericCellValue());
cellValue = cellValue.replace(" ", "|").replace("\n", "|").replace("\r", "|").replace("\t",
"|");
cellValue = DataImportUtils.qj2bj(cellValue);
} else {
cell_.setCellType(HSSFCell.CELL_TYPE_STRING);
cellValue = cell_.toString().replace(" ", "|").replace("\n", "|").replace("\r", "|")
.replace("\t", "|");
cellValue = DataImportUtils.qj2bj(cellValue);
}
// 设置存入内容为字符串
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
// 向单元格中放入值
cell.setCellValue(cellValue);
return true;
}
}
}
return false;
}
e.将单元格格式转换
/**
* 将单元格格式转换
*
* @param cell
* @return
*/
public static String setCellStyle(Cell cell) {
String cellValue = "";
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
DecimalFormat df = new DecimalFormat("#");
cellValue = df.format(cell.getNumericCellValue());
cellValue = cellValue.replace(" ", "|").replace("\n", "|").replace("\r", "|").replace("\t", "|");
cellValue = DataImportUtils.qj2bj(cellValue);
} else {
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
String c = cell.toString().replace(" ", "|").replace("\n", "|").replace("\r", "|").replace("\t", "|");
cellValue = DataImportUtils.qj2bj(c);
}
return cellValue;
}
f.测试一下
public static void method28(){
String sb = ExcelUtil.getContent01("G:\\xx\\test__.xlsx");
System.out.println(sb);
}
测试文件大致就是弄一个合并单元格,任意位置,空单元格,空行,单元格内容存在换行等分隔符。
由于我的测试文件内容为敏感内容(我自己的手机号,住址等信息),不方便贴出来,望各位见谅!!