如何使用 shiftColumns 方法删除列
How to delete column with shiftColumns method
我想使用 Apache POI 5.0.0 删除 Excel (XLSX) 中的一列。我想使用 shiftColumns
方法,因此受影响的公式会自动调整。
void shiftColumns(int startColumn, int endColumn, int n)
https://poi.apache.org/apidocs/dev/org/apache/poi/ss/usermodel/Sheet.html
文档说,如果你想左移(覆盖左侧的列),你应该使用负数。
我在以下 Excel 文件上尝试了以下示例:
String path = "pathOfTheExcelFile";
File file = new File(path);
Workbook wb = null;
try (FileInputStream inputStream = new FileInputStream(file)) {
wb = WorkbookFactory.create(inputStream); // read workbook
} catch (IOException e) {
e.printStackTrace();
}
if(wb == null)
return;
Sheet sheet = wb.getSheetAt(0); // read first sheet
// deleting / overriding 2nd column
sheet.shiftColumns(2, 5, -1); // shifting from 3rd to last column to the left
try (OutputStream fileOut = new FileOutputStream(path)) {
wb.write(fileOut); // writing the result in the Excel file (ERROR)
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (wb != null)
wb.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
Excel 我要修改的文件:
执行代码后,我在第 wb.write(fileOut);
行收到此错误:
java.lang.IndexOutOfBoundsException
at org.apache.xmlbeans.impl.store.Xobj.removeElement(Xobj.java:2099)
at org.apache.xmlbeans.impl.store.Xobj.remove_element(Xobj.java:2130)
at org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTRowImpl.removeC(CTRowImpl.java:173)
at org.apache.poi.xssf.usermodel.XSSFRow.fixupCTCells(XSSFRow.java:612)
at org.apache.poi.xssf.usermodel.XSSFRow.onDocumentWrite(XSSFRow.java:582)
at org.apache.poi.xssf.usermodel.XSSFSheet.write(XSSFSheet.java:3625)
at org.apache.poi.xssf.usermodel.XSSFSheet.commit(XSSFSheet.java:3570)
at org.apache.poi.ooxml.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:465)
at org.apache.poi.ooxml.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:470)
at org.apache.poi.ooxml.POIXMLDocument.write(POIXMLDocument.java:221)
at test.App.main(App.java:38)
仅供参考,我使用 Java 11 和这些库:
libraries
执行后,我的文件有0KB。
我在将工作簿保存在 Excel 文件中时调试了 Apache POI 库。这是问题开始的地方。也许对你有帮助:
pic1
pic2
pic3
是的,即使在最新版本的 Apache POI 5.1.0 中,Sheet.shiftColumns 仍然存在问题。 shiftColumns
在负向移动时没有正确删除单元格。这就是为什么写的时候出错了。
如果您明确删除要过度移动的列的单元格,则错误消失。因此,在将第三列(索引 2)向左移动之前,我们需要从第二列(索引 1)中删除所有单元格。
但是还有其他问题。即使是最新版本也不会在移动公式时更新计算链。这就是这个Q/A的问题:.
完整示例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.model.CalculationChain;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import java.lang.reflect.Method;
public class ExcelShiftColums {
private static void removeCalcChain(XSSFWorkbook workbook) throws Exception {
CalculationChain calcchain = workbook.getCalculationChain();
Method removeRelation = POIXMLDocumentPart.class.getDeclaredMethod("removeRelation", POIXMLDocumentPart.class);
removeRelation.setAccessible(true);
removeRelation.invoke(workbook, calcchain);
}
private static void removeColumn(Sheet sheet, int column) {
for (Row row : sheet) {
Cell cell = row.getCell(column);
if (cell != null) {
row.removeCell(cell);
}
}
}
private static int getLastFilledColumn(Sheet sheet) {
int result = 0;
for (Row row : sheet) {
if (row.getLastCellNum() > result) result = row.getLastCellNum();
}
return result;
}
public static void main(String[] args) throws Exception {
String inFilePath = "./ExcelExampleIn.xlsx"; String outFilePath = "./ExcelExampleOut.xlsx";
//String inFilePath = "./ExcelExampleIn.xls"; String outFilePath = "./ExcelExampleOut.xls";
try (Workbook workbook = WorkbookFactory.create(new FileInputStream(inFilePath));
FileOutputStream out = new FileOutputStream(outFilePath ) ) {
Sheet sheet = workbook.getSheetAt(0);
int lastFilledColumn = getLastFilledColumn(sheet);
removeColumn(sheet, 1);
sheet.shiftColumns(2, lastFilledColumn, -1);
if (workbook instanceof XSSFWorkbook) removeCalcChain((XSSFWorkbook)workbook);
workbook.write(out);
}
}
}
我想使用 Apache POI 5.0.0 删除 Excel (XLSX) 中的一列。我想使用 shiftColumns
方法,因此受影响的公式会自动调整。
void shiftColumns(int startColumn, int endColumn, int n)
https://poi.apache.org/apidocs/dev/org/apache/poi/ss/usermodel/Sheet.html
文档说,如果你想左移(覆盖左侧的列),你应该使用负数。
我在以下 Excel 文件上尝试了以下示例:
String path = "pathOfTheExcelFile";
File file = new File(path);
Workbook wb = null;
try (FileInputStream inputStream = new FileInputStream(file)) {
wb = WorkbookFactory.create(inputStream); // read workbook
} catch (IOException e) {
e.printStackTrace();
}
if(wb == null)
return;
Sheet sheet = wb.getSheetAt(0); // read first sheet
// deleting / overriding 2nd column
sheet.shiftColumns(2, 5, -1); // shifting from 3rd to last column to the left
try (OutputStream fileOut = new FileOutputStream(path)) {
wb.write(fileOut); // writing the result in the Excel file (ERROR)
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (wb != null)
wb.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
Excel 我要修改的文件:
执行代码后,我在第 wb.write(fileOut);
行收到此错误:
java.lang.IndexOutOfBoundsException
at org.apache.xmlbeans.impl.store.Xobj.removeElement(Xobj.java:2099)
at org.apache.xmlbeans.impl.store.Xobj.remove_element(Xobj.java:2130)
at org.openxmlformats.schemas.spreadsheetml.x2006.main.impl.CTRowImpl.removeC(CTRowImpl.java:173)
at org.apache.poi.xssf.usermodel.XSSFRow.fixupCTCells(XSSFRow.java:612)
at org.apache.poi.xssf.usermodel.XSSFRow.onDocumentWrite(XSSFRow.java:582)
at org.apache.poi.xssf.usermodel.XSSFSheet.write(XSSFSheet.java:3625)
at org.apache.poi.xssf.usermodel.XSSFSheet.commit(XSSFSheet.java:3570)
at org.apache.poi.ooxml.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:465)
at org.apache.poi.ooxml.POIXMLDocumentPart.onSave(POIXMLDocumentPart.java:470)
at org.apache.poi.ooxml.POIXMLDocument.write(POIXMLDocument.java:221)
at test.App.main(App.java:38)
仅供参考,我使用 Java 11 和这些库:
libraries
执行后,我的文件有0KB。
我在将工作簿保存在 Excel 文件中时调试了 Apache POI 库。这是问题开始的地方。也许对你有帮助:
pic1
pic2
pic3
是的,即使在最新版本的 Apache POI 5.1.0 中,Sheet.shiftColumns 仍然存在问题。 shiftColumns
在负向移动时没有正确删除单元格。这就是为什么写的时候出错了。
如果您明确删除要过度移动的列的单元格,则错误消失。因此,在将第三列(索引 2)向左移动之前,我们需要从第二列(索引 1)中删除所有单元格。
但是还有其他问题。即使是最新版本也不会在移动公式时更新计算链。这就是这个Q/A的问题:
完整示例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.model.CalculationChain;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import java.lang.reflect.Method;
public class ExcelShiftColums {
private static void removeCalcChain(XSSFWorkbook workbook) throws Exception {
CalculationChain calcchain = workbook.getCalculationChain();
Method removeRelation = POIXMLDocumentPart.class.getDeclaredMethod("removeRelation", POIXMLDocumentPart.class);
removeRelation.setAccessible(true);
removeRelation.invoke(workbook, calcchain);
}
private static void removeColumn(Sheet sheet, int column) {
for (Row row : sheet) {
Cell cell = row.getCell(column);
if (cell != null) {
row.removeCell(cell);
}
}
}
private static int getLastFilledColumn(Sheet sheet) {
int result = 0;
for (Row row : sheet) {
if (row.getLastCellNum() > result) result = row.getLastCellNum();
}
return result;
}
public static void main(String[] args) throws Exception {
String inFilePath = "./ExcelExampleIn.xlsx"; String outFilePath = "./ExcelExampleOut.xlsx";
//String inFilePath = "./ExcelExampleIn.xls"; String outFilePath = "./ExcelExampleOut.xls";
try (Workbook workbook = WorkbookFactory.create(new FileInputStream(inFilePath));
FileOutputStream out = new FileOutputStream(outFilePath ) ) {
Sheet sheet = workbook.getSheetAt(0);
int lastFilledColumn = getLastFilledColumn(sheet);
removeColumn(sheet, 1);
sheet.shiftColumns(2, lastFilledColumn, -1);
if (workbook instanceof XSSFWorkbook) removeCalcChain((XSSFWorkbook)workbook);
workbook.write(out);
}
}
}