2

每当我尝试使用模板创建 xls 时使用 jxl API 运行到奇怪的 ArrayIndexOutOfBoundException。这是我尝试使用的代码片段

private static void readWorkSheet()throws Exception{
            File file = new File("C:\\reports\\");
            Map template = new HashMap();
            File[] listFiles = file.listFiles();
            for(File file1:listFiles){
                if(file1.getName().endsWith(".xls")){
                    System.out.println(" ==> "+file1.getName());
                    Workbook workbookTemplate = Workbook.getWorkbook(file1);
                    template.put(file1.getName(), workbookTemplate);
                }

            }
            System.out.println("template "+template);
            Workbook templateWorkBook = (Workbook)template.get("TestReport.xls");
            Sheet readSheet = templateWorkBook.getSheet("Sheet1");

            WritableWorkbook copy = Workbook.createWorkbook(new File("c://myfile_copy2.xls"));

            WritableSheet sheet = copy.createSheet("Test", 0);
            for (int i = 0; i < readSheet.getRows(); i++) {
                for (int j = 0; j < readSheet.getColumns(); j++) {
                    Cell readCell = readSheet.getCell(j, i);
                    CellFormat readFormat = readCell.getCellFormat();
                    if(readFormat != null && readCell.getContents() != null && readCell.getContents() != ""){
                        WritableCell newCell = new Label(i,j,readCell.getContents());
                        WritableCellFormat newFormat = new WritableCellFormat(readFormat);
                        newCell.setCellFormat(newFormat);
                        System.out.println("details of cell ["+i+", "+j+"]"+" Name = "+readCell.getContents());
                        System.out.println("details of newCell ["+i+", "+j+"]"+" Name = "+newCell.getContents());
                        sheet.addCell(newCell);
                    }
                }
        }
            copy.write();
            copy.close(); 
        }

不知道我在这缺少什么!!!

我遇到的异常

  Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 56
    at jxl.biff.IndexMapping.getNewIndex(IndexMapping.java:68)
    at jxl.biff.XFRecord.rationalize(XFRecord.java:1667)
    at jxl.biff.FormattingRecords.rationalize(FormattingRecords.java:443)
    at jxl.write.biff.WritableWorkbookImpl.rationalize(WritableWorkbookImpl.java:1023)
    at jxl.write.biff.WritableWorkbookImpl.write(WritableWorkbookImpl.java:701)
    at com.jxl.test.JXLTest.readWorkSheet(JXLTest.java:83)
    at com.jxl.test.JXLTest.main(JXLTest.java:30)
4

3 回答 3

3

我面临同样的问题。但只有当我尝试通过同一类创建多个 excel 文件时才会发生这种情况。意味着如果我通过一个junit测试创建两个文件,它就会发生。如果我通过两个单独的单元测试类来做到这一点,一切都很好。我只是在 jxl 代码中寻找一种强引用。
在那之前我找到了一个解决方法:

WorkbookSettings wbSettings = new WorkbookSettings();
wbSettings.setRationalization(false);

该问题是由 FormattingRecords.rationalize() 方法引起的。上面的这个设置切换了合理化过程。DateFormats 和 NumberFormats 等将起作用,这样做会使单元格格式的 WritableFonts 丢失。

请继续关注-也许我会找到更多。

...我发现更多:主要问题是 jxl.biff.Fonts 类未正确重新初始化,仅包含 4 个默认 FontRecord 实体。我挖得更深了,发现在XFRecord类的initialize方法中有一个if语句:

if (!font.isInitialized())
{
   fonts.addFont(font);
}

第一次没有初始化字体并将成功添加到此处。对于所有其他迭代,字体被初始化并且不会被添加。不知道谁拥有 XFRecords 以及为什么它没有正确刷新。但我找到了一个可行的解决方法:

@SuppressWarnings("unchecked")
private void adjustUsedFonts(WritableWorkbook workbook) throws NoSuchFieldException, IllegalAccessException {
    WritableWorkbookImpl workbookImpl = (WritableWorkbookImpl) workbook;
    Field fontsField = WritableWorkbookImpl.class.getDeclaredField("fonts");
    fontsField.setAccessible(true);
    Fonts fonts = (Fonts) fontsField.get(workbookImpl);
    Field fontsListField = Fonts.class.getDeclaredField("fonts");
    fontsListField.setAccessible(true);
    ArrayList<FontRecord> fontRecords = (ArrayList<FontRecord>) fontsListField.get(fonts);
    // just to get to know which fonts are available
    for (FontRecord fontRecord : fontRecords) {
        logger.info("found font: name={}; size={}", fontRecord.getName(), fontRecord.getPointSize());
    }
    // DON'T DO THIS HARDCODED LIKE THIS 
    // BUT CHECK IF YOUR FONTS ARE AVAILABLE AND ADD IF NOT
    if (fontRecords.size() == 4) {
        logger.info("only 4 fonts available - add necessary ones");
        fontRecords.add(tableDefaultFont);
    }
}

我把这个方法放在调用workbook.write方法的前面。它适用于所有字体。我知道这是一个 hack,没有好的解决方案。这就是为什么我会在他们的 Ticket-Queue 中打开一个问题(黑客只适用于那些不能等到修复可用的人)。

我使用了这个版本的 jxl,它似乎是最新的:
groupId: net.sourceforge.jexcelapi
artifactId: jxl
version: 2.6.12

添加:如果您有多个自己的字体,您还需要使用其 fontIndex 以正确的顺序添加它。否则字体会混淆。我写了一个有用的方法来找出正确的索引:

    private void determineFontIndizesOfOwnFonts(WritableWorkbook workbook) throws NoSuchFieldException, IllegalAccessException {
    WritableWorkbookImpl workbookImpl = (WritableWorkbookImpl) workbook;
    Field frField = WritableWorkbookImpl.class.getDeclaredField("formatRecords");
    frField.setAccessible(true);
    FormattingRecords formRecords = (FormattingRecords) frField.get(workbookImpl);
    Field xfRecordListField = FormattingRecords.class.getDeclaredField("xfRecords");
    xfRecordListField.setAccessible(true);
    ArrayList<XFRecord> xfRecords = (ArrayList<XFRecord>) xfRecordListField.get(formRecords);
    logger.debug("amount of xfRecords: {}", xfRecords.size());
    for (XFRecord curXfRecord : xfRecords) {
        Font curFont = curXfRecord.getFont();
        if (curFont.equals(tableHeaderFont)) {
            logger.debug("font 'tableHeaderFont' info: idx={}, initialized={}, font[{}, {}px]", curXfRecord.getFontIndex(), curXfRecord.isInitialized(),
                    curFont.getName(), curFont.getPointSize());
            if (!fontIdxToName.containsKey(curXfRecord.getFontIndex())) {
                fontIdxToName.put(curXfRecord.getFontIndex(), tableHeaderFont);
            }
        }
        if (curFont.equals(tableContentFont)) {
            logger.debug("font 'tableContentFont' info: idx={}, initialized={}, font[{}, {}px]", curXfRecord.getFontIndex(), curXfRecord.isInitialized(),
                    curFont.getName(), curFont.getPointSize());
            if (!fontIdxToName.containsKey(curXfRecord.getFontIndex())) {
                fontIdxToName.put(curXfRecord.getFontIndex(), tableContentFont);
            }
        }
        if (curFont.equals(tableImportantOrFooterFont)) {
            logger.debug("font 'tableImportantOrFooterFont' info: idx={}, initialized={}, font[{}, {}px]", curXfRecord.getFontIndex(),
                    curXfRecord.isInitialized(), curFont.getName(), curFont.getPointSize());
            if (!fontIdxToName.containsKey(curXfRecord.getFontIndex())) {
                fontIdxToName.put(curXfRecord.getFontIndex(), tableImportantOrFooterFont);
            }
        }
    }
}

然后只需按正确的顺序添加它,请参阅其他方法。

于 2014-03-05T09:40:18.397 回答
1

我也遇到了这个问题,版本 2.4.2 和 2.6.12。

我通过不再使任何 Fonts / DisplayFormats / WritableCellFormats 对象成为静态来解决它。

公平地说,我确实在这里找到了解决方案: http ://www.logikdev.com/2010/01/18/writablefont-doesnt-like-to-be-static/ 其中还引用了 JExcelAPI 常见问题解答:

来自http://jexcelapi.sourceforge.net/resources/faq/

“另外,重要的是不要将单元格格式声明为静态。将单元格格式添加到工作表时,会为其分配一个内部索引号。如果您有两个线程(例如在 Web 环境中)编写两个不同的电子表格,格式编号会混淆,生成的工作表可能已损坏或不正确。”</p>


编辑:基于评论的一点澄清。

最初我的实现是这样的:

public class SomeExcelThing() { 
   private final static MY_FONT = new Font(); 

   public createCell() { 
      return new Cell(MY_FONT);
   }
}

因为它现在每次创建新单元格时都重新使用相同的 Font 对象,所以它给出了该错误。所以后来我把它改成了:

public class SomeExcelThing() {
   public createCell() {
      return new Cell(new Font());
   }
}

因此,您不应该将 Fonts、DisplayFormats、WritableCellFormats 设为常量,因为它们会产生这些错误。所以如果你想重用某种字体,我会创建一个方法来获取你想要的字体,每次都会创建一个新的字体对象,而不是使用常量:

public class SomeExcelThing() {
   public createCell() {
      return new Cell(getMyFont());
   }

   private Font getMyFont() {
      return new Font();
   }
}
于 2019-06-25T09:34:43.317 回答
0

我也面临同样的问题。我正在使用 JXL 库 2.6.12。我正在使用两个不同的“.xls”文件,并应用了 3 种不同的 WritableCellFormat 样式。当我在两个“.xls”单元格中使用相同的三个可写格式对象时,它导致了问题。

解决方案:
我创建了一个方法,在该方法中为 WritableCellFormat 创建不同的对象。我分别在创建“.xls”工作簿时调用了这个方法。这是因为,两个“.xls”文件工作簿的创建都是使用不同的可写单元格格式对象完成的。

于 2015-05-22T04:34:01.390 回答