Java操作excel
前两天遇到一个这样的任务,需要将十多个Excel按指定模板整理,这种情况首先想到的就是用程序去解决这件事,人工的话,不仅费时费力,而且准确度不一定高,偶尔马虎一下,很难再去发现,最主要的是我们人力不够,就两个人,要整的话得一两天的工作量,但是领导给的时间也不是很多,遂用代码解决。
一开始想到的是用python去写,但是换了电脑后还没装python环境,而且用python也不是特别多,写的话肯定是一边写一边学,如果时间充裕的话,这是最好的解决办法,但是奈何时间不是很多,就直接拿java写了。
之前写过用java读取excel,这次是在两个excel间对比,写入第三个excel,涉及到整列数据的读取写入,两个sheet页首行数据的对比,多个sheet页之间的操作等。
没写之前不知道,写完之后发现java操作excel还是比较不友好的,主要包括两点,
1.java操作excel一般是用poi操作,poi操作不支持整列操作,一般都是按行操作,所以对于我的需求就比较难受了,每次操作列只能先读行,再读列,写入同理;
2.一开始设想的是按列操作完成之后,保存再写入下一列,但是发现新建excel时写入数据没问题,但是再追加数据就不行了,网上找了半天,只发现两种解决方法,很不幸,都不行;
对于第一种情况,没有办法,只能先读行,再读列,难受也没办法;对于第二种情况,有两种解决办法,要么就是读取完整个excel后再写入,要么就是读取原excel,然后增加要写入的数据,再写入到新的文件中,我是用第一种方法,通过二维数组记录下整个要写入的表格,然后通过二维数组写入到表格中。
现在记录下中间关键的几个操作点:
- 读取文件列表:
// 读取某目录
File dir = new File(strPath);
// 获取文件夹下某所有文件
File[] files = dir.listFiles();
- 读取Excel文件
// 新建文件流
FileInputStream templateFileInputStream = null;
// 新建sheet对象
XSSFWorkbook sheets = null;
// 新建excel行
XSSFRow row = null;
try {
// 读取文件流
templateFileInputStream = new FileInputStream(filePath);
// 解析xlsx格式文件
sheets = new XSSFWorkbook(templateFileInputStream);
// 获取指定sheet
XSSFSheet sheet = sheets.getSheetAt(sheetIndex);
// 获取第一行
row = sheet.getRow(0);
// 获取当前行包含列数
int columns = row.getPhysicalNumberOfCells();
// 获取当前表格行数
int physicalNumberOfRows = sheet.getPhysicalNumberOfRows();
jsonObject.put("row", row);
jsonObject.put("columns", columns);
jsonObject.put("rows", physicalNumberOfRows);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (templateFileInputStream != null) {
templateFileInputStream.close();
}
}
- 写入excel文件
//1、判断文件是否存在,存在的话,就追加新的sheet页,不存在就新建
FileOutputStream out = null;
// 声明一个工作薄
XSSFWorkbook workbook = null;
try {
out = new FileOutputStream(newFilePath);
workbook = new XSSFWorkbook();
// 生成一个表格
XSSFSheet sheet = workbook.createSheet(title);
// array是要写入的二维数组,可以换成其他
for (int i = 0; i < array[0].length; i++) {
// a是我代码中的一个值,createRow这个方法是创建下标为a的行
XSSFRow row = sheet.createRow(a);
for (int j = 0; j < array.length; j++) {
XSSFCell cell = row.createCell(j);
cell.setCellValue(array[j][i]);
}
// 将建好的sheet写入到excel中
workbook.write(out);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
}
- 单元格类型判断
switch (cell.getCellTypeEnum()) {
case STRING:
temp = cell.getRichStringCellValue().getString();
break;
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
temp = df.format(date);
} else if (!String.valueOf(cell.getNumericCellValue()).contains("E")) {
return String.valueOf(cell.getNumericCellValue());
} else {
// 对超长字符串进行格式化处理
return new DecimalFormat("#").format(cell.getNumericCellValue());
}
break;
case BLANK:
temp = "";
break;
default:
temp = cell.toString();
break;
}
已上就是处理的主要步骤,不过因为时间原因代码只实现了主要功能,算是半自动化吧,还得手动切换数据模板,不过这样已经可以顺利完成任务了,比全自动慢了一丢丢,从上边的2,3点就可以看出为什么支持追加了,对于同一个文件,不可能同时对它进行读入流和写入流操作,所以不能追加,再后边第四点写的比较简单,因为当前数据格式不是很多,这几个足以满足要求,如果有需要可以去网上找下,有不少例子可以参考。