合併行_Java POI Excel移動行和複製行的處理
阿新 • • 發佈:2021-01-14
技術標籤:合併行
Java POI Excel移動行和複製行的處理
POI操作Excel時,不支援移動行的操作,因此在需要通過複製行+刪除行+建立空白行的組合方式來達成移動行的效果。
坑點:
- POI操作Excel文件和Excel軟體操作文件的理解是不一樣的,Excel軟體日常操作時不是嚴格區分
空白行
和空行
,而POI操作時必須嚴格區分,空白行可以直接操作,而空行則必須先執行建立行操作後才能操作。 copyRows
複製行從源位置到目標位置時,不是完全覆蓋模式,因此如果目標區域有內容,會用源區域有內容的部分替換到目標區域的內容,源區域沒有內容的部分仍會使用目標區域的內容。這個和Excel軟體操作中複製區域貼上到指定區域的操作的效果是不同的。另外copyRows
空行
的行,例如如果想將3-5
行開始複製到7-9
行,如果3、4
行是空行
,那麼拷貝後的結果為為7
行為5
行的內容。removeRow
刪除行時,只會刪除行的資料,對於行的合併單元格等資料不會刪除,因為合併單元格是存放在sheet
上。因此如果想同時刪除合併單元格,則需要先手動刪除合併單元格,再刪除行。由於合併單元格資料是存放在一個list上的,而刪除只提供下標刪除方式,因此刪除時需要按照下標大小倒序刪除。copyRows
可以將源行的內容和樣式都拷貝到目標行。- 使用複製行+刪除行+建立空白行組合方式達到移動行的效果時,需要注意臨時區域的位置,保證臨時區域不會和最終結果有重疊區域。
實現的程式碼
if(CollectionUtils.isNotEmpty(dataList)) { int beginRowNo = data.getBeginRow(); Row beginRow = sheet.getRow(beginRowNo); int addNo = dataList.size(); int moveBeginRow = beginRowNo+1; //如果移動的開始行不存在,則建立一個空行,否則複製的時候會丟掉不存在的行 if(sheet.getRow(moveBeginRow)==null){ sheet.createRow(moveBeginRow); } int lastRowNo = sheet.getLastRowNum(); //計算移動的行數 int movedNo = lastRowNo-moveBeginRow+1; //臨時區的開始行 int tempBeginRowNo = lastRowNo+addNo+1; //臨時區的結束行 int tempLastRowNo = tempBeginRowNo+movedNo-1; //末尾部分的最終開始行 int finalBeginRowNo = addNo+beginRowNo; //移動開始行以後的行到臨時的開始行 moveRows(sheet,moveBeginRow,lastRowNo,tempBeginRowNo); //在空出位置插入新行並複製第一行的樣式 for (int i = moveBeginRow; i <finalBeginRowNo; i++){ Row row = sheet.getRow(i); if (row != null){ sheet.removeRow(row); } //建立空白的行 sheet.createRow(i); if(beginRow!=null){ //複製第一行的樣式到當前行 sheet.copyRows(beginRowNo,beginRowNo, i, DEFAULT_ROW_COPY_POLICY); } } //將移動的行從臨時開始行回移新增好的行的末尾 /* 為什麼不直接第一次移動的預期的末尾呢?是因為POX只支援Copy行的操作,而copy操作不是完整的區間覆蓋。 如果源區間內帶有格式,並且目的區間和源區間有重疊話,會導致無法copy後源區間和目的區間混合在一起,無法清理。 因此實現移動行區間的操作時,需要先將源行區間複製到一個臨時的區域,然後清理掉源行區間的行和樣式,再插入需要新增的行 ,最後再將被移動的行區間移動回新的行末尾。 */ moveRows(sheet,tempBeginRowNo,tempLastRowNo,finalBeginRowNo); } /** * 移動指定行區間到指定位置,並刪除移動後原地的行 * @author 徐明龍 XuMingLong 2019-06-27 * @param sheet * @param srcBeginRow * @param srcEndRow * @param destBeginRow * @return void */ private static void moveRows(XSSFSheet sheet,int srcBeginRow,int srcEndRow,int destBeginRow){ //先複製到目的位置 sheet.copyRows(srcBeginRow, srcEndRow, destBeginRow, DEFAULT_ROW_COPY_POLICY); //清理之前殘留的合併單元格 List<Integer> removeMergedRegion = new ArrayList<>(); for(int i=sheet.getMergedRegions().size()-1;i>=0;i--){ CellRangeAddress address = sheet.getMergedRegions().get(i); //如果合併單元格在複製前的位置,則刪除 if(address.getFirstRow() >= srcBeginRow && address.getFirstRow()<destBeginRow ){ removeMergedRegion.add(i); } }; //執行清理合並的單元格 for(Integer i:removeMergedRegion){ sheet.removeMergedRegion(i); } //刪除移動後原地的行 for (int i = srcBeginRow; i <= srcEndRow; i++){ Row row = sheet.getRow(i); if (row != null){ //刪除複製後殘留的行 sheet.removeRow(row); } } }