前兩天遇到一個這樣的任務,需要將十多個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點就可以看出為什么支持追加了,對於同一個文件,不可能同時對它進行讀入流和寫入流操作,所以不能追加,再后邊第四點寫的比較簡單,因為當前數據格式不是很多,這幾個足以滿足要求,如果有需要可以去網上找下,有不少例子可以參考。