尝试将内容从一张纸复制到另一张纸时,jxl api 出现 ArrayIndexOutOfBoundException

发布于 2024-12-19 16:17:08 字数 2630 浏览 5 评论 0原文

每当我尝试使用模板使用 jxl API 创建 xls 时,都会遇到奇怪的 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)

Whenever I am trying to use template to create xls using jxl API running into weird ArrayIndexOutOfBoundException.
Here is the snippet of code I am trying to use

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(); 
        }

Not sure what I am missing in this !!!

Exception I am running into

  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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

独留℉清风醉 2024-12-26 16:17:08

我面临同样的问题。但只有当我尝试通过同一类创建多个 Excel 文件时才会发生这种情况。意味着如果我通过一个 junit 测试创建两个文件,就会发生这种情况。如果我通过两个单独的单元测试类来执行此操作,则一切正常。我只是在 jxl 代码中寻找一种强引用。
直到那时我找到了一个解决方法:

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

问题是由于 FormattingRecords.rationalize() 方法而发生的。上述设置会切换合理化过程。 DateFormats 和 NumberFormats 等可以工作但是,这样做您将丢失单元格格式的 WritableFonts。

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

...我发现更多:
主要问题是 jxl.biff.Fonts 类未正确重新初始化,并且仅包含 4 个默认 FontRecord 实体。我进一步挖掘,发现在 XFRecord 类的初始化方法中,有一个 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 方法之前。并且所有字体都可用。
我知道这是一个黑客行为,没有好的解决方案。这就是为什么我会在他们的票务队列中提出一个问题(该黑客仅适用于那些迫不及待修复可用的人)。

我用的是这个版本的jxl,它似乎是最新的:
组ID:net.sourceforge.jexcelapi
工件ID:jxl
版本: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);
            }
        }
    }
}

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

I face the same problem. But it occurs only if I try to create more than one excel file by the same class. Means if i create two files by one junit test it occurs. If I do this by two separate unit test classes everything works fine. I am just searching for a kind of strong reference in the jxl code.
Until then I found a Workaround:

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

The problem occurs due to the FormattingRecords.rationalize() method. This setting above switches of the rationalization process. DateFormats and NumberFormats and so on will work BUT you will loose the WritableFonts for the cell format by doing this.

Stay tuned - maybe I will find more.

... I found more:
The main problem is that the jxl.biff.Fonts class is not reinitialized correctly and only contains the 4 default FontRecord entities. I dug a bit deeper and found that in the initialize method of the XFRecord class there is an if statement:

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

For the very first time a font is not initialized and will be added here successfully. For all other iterations the font is initialized and won't be added. No idea who holds the XFRecords and why it isn't refreshed correctly. But I found a working workaround:

@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);
    }
}

I put this method in front of calling the workbook.write method. And it works all fonts are available.
I know this is a hack and no good solution. This is why I will open an issue at their Ticket-Queue (the hack is only for those who cannot wait until the fix is available).

I used this version of jxl and it seemed to be the latest:
groupId: net.sourceforge.jexcelapi
artifactId: jxl
version: 2.6.12

ADDITION:
If you have more than one own font you will also need to add it in the right order by using its fontIndex. Otherwise fonts will be mixed up. I wrote a helpful method to find out the right index:

    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);
            }
        }
    }
}

then afterwards just add it in the right order see other method.

时光磨忆 2024-12-26 16:17:08

我刚刚也遇到了这个问题,版本 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/< /p>

“另外,不要将单元格格式声明为静态,这一点很重要。当单元格格式添加到工作表时,它会被分配一个内部索引号。如果您有两个线程(例如在 Web 环境中)编写两个不同的电子表格,则格式数字会变得混乱,并且生成的工作表可能会损坏或不正确。”


编辑:基于评论的澄清。

最初我的实现是这样的:

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();
   }
}

I have just had this problem as well, both with version 2.4.2 and 2.6.12.

I solved it by no longer making any of the Fonts / DisplayFormats / WritableCellFormats objects static.

To be fair, I did find the solution here:
http://www.logikdev.com/2010/01/18/writablefont-doesnt-like-to-be-static/
Which also references the JExcelAPI FAQ:

From http://jexcelapi.sourceforge.net/resources/faq/

“also, it’s important that you Do Not declare your cell formats as static. As a cell format is added to a sheet, it gets assigned an internal index number. If you have two threads (such as in a Web environment) writing two different spreadsheets, the format numbers will get confused and the resulting sheet could either be corrupted or incorrect.”


Edit: little clarification based on comments.

Initially my implementation was like this:

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

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

Because it was now re-using the same Font object everytime a new cell was created, it gave that error. So then I changed it around to be:

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

So you should not make a constant out of Fonts, DisplayFormats, WritableCellFormats, as these would create these errors. So if you want to reuse a certain font, I would create a method to get the font you want, which would each time create a new font-object, instead of using a constant:

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

   private Font getMyFont() {
      return new Font();
   }
}
笑忘罢 2024-12-26 16:17:08

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

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

I was also facing the same problem. I am using JXL library 2.6.12.
I was working with two different ".xls" files and was applying 3 different WritableCellFormat styles. When I was using the same three writable format objects in both the ".xls" cells, it was causing the problem.

Solution:
I have created a method where I am creating different objects for WritableCellFormat. I called this method on both ".xls" workbook creation, separately. This worked as, both ".xls" files workbook creation is done with different objects of writable cell format.

不弃不离 2024-12-26 16:17:08

试试这个

// make sure you only use .xls extension
    String filepath = "/Users/username/Downloads/Projects/Java/jExcelProject/reports/file.xls";
    Workbook workbook = Workbook.getWorkbook(new File(filePath));

try this

// make sure you only use .xls extension
    String filepath = "/Users/username/Downloads/Projects/Java/jExcelProject/reports/file.xls";
    Workbook workbook = Workbook.getWorkbook(new File(filePath));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文