JXL调用copySheet()和importSheet()方法时报异常

处理EXCEL的开源java util中我了解的有JXL、POI。
而我一直是用jxl来处理excel文件的,之前只是用它来做简单的读写等操作,因此觉得这个jxl还是比较简单轻便的。然而,最近项目中客户有一个带宏(Macro)的sheet要做处理,而JXL貌似在处理带宏的excel方面有些局限(不是一点点),不是很能够处理这方面内容。
我查看了jxl的API文档,发现在jxl.WorkbookSettings中有这么一段:
引用

setPropertySets(boolean r)
          Sets whether or not to enable any property sets (such as macros) to be copied along with the workbook Leaving this feature enabled will result in the JXL process using more memory


因为我不需要对宏做任何修改,只是简单地想把这个宏拷贝下来,因此我认为我只需要将以上这个方法置true,然后再调用copySheet()或者importSheet()方法拷贝这个sheet,应该就能把这个带宏的sheet拷贝下来。

但是当我这样做的时候,我发现我在copySheet()方法中捕获了一个异常,显示如下:
引用

java.lang.NullPointerException
at java.lang.String.compareTo(Unknown Source)
at java.lang.String.compareTo(Unknown Source)
at java.util.Arrays.binarySearch0(Unknown Source)
at java.util.Arrays.binarySearch(Unknown Source)
at jxl.write.biff.SheetCopier.importNames(SheetCopier.java:1049)
at jxl.write.biff.SheetCopier.importSheet(SheetCopier.java:784)
at jxl.write.biff.WritableSheetImpl.importSheet(WritableSheetImpl.java:2638)
at jxl.write.biff.WritableWorkbookImpl.importSheet(WritableWorkbookImpl.java:1897)
at test_JXL.Test_JXL_copysheet.<init>(Test_JXL_copysheet.java:62)
at test_JXL.Test_JXL_copysheet.main(Test_JXL_copysheet.java:80)


于是,我在网上搜索了一下,关于这个“JXL的copySheet()方法出现异常”,看到在OSChina讨论组里有一篇跟我遇到一样情况的人写的帖子:
这两天使用Jexcel进行copySheet时总是报异常:
java.lang.NullPointerException  
        at jxl.write.biff.WritableSheetCopier.shallowCopyCells(WritableSheetCopier.java:499) [jxl.ja  
r:na]  
        at jxl.write.biff.WritableSheetCopier.copySheet(WritableSheetCopier.java:239) [jxl.jar:na]  
        at jxl.write.biff.WritableSheetImpl.copy(WritableSheetImpl.java:1622) [jxl.jar:na]  
        at jxl.write.biff.WritableWorkbookImpl.copySheet(WritableWorkbookImpl.java:987) [jxl.jar:na]  

今天跟了下jexcel的源代码,发现在jxl.write.biff.WritableSheetCopier.shallowCopyCells方法中
if (c.getCellFeatures() != null & c.getCellFeatures().hasDataValidation())  
{  
    validatedCells.add(c);  
} 

代码中少写了一个&符,虽然也可以用来表示“且”的逻辑,但一个&符是没有用到短路算法的,这样就会导致不 管&前面表达式的结果是true还是flase,&符后面的表达式都会执行。在这段代码中,在c.getCellFeatures()是 null 的情况下,c.getCellFeatures().hasDataValidation()必然会报 java.lang.NullPointerException异常。

http://www.oschina.net/question/42346_67474

我在jxl的原站上 http://www.andykhan.com/jexcelapi/download.html下载了最新版本的源包,并查看了源码,发现确实如以上网友所言。

并且,我在网上找到了一个jxl.jar(688 KB),这个jar包与最新版本有区别,我调用这个包就不会出异常,我想应该是好心人已经把源码修正了并打包成jar包,这里我也把它贴出来,好方便大家使用,省得自己还得修改源码再打包,浪费时间。

现在,用新jxl包,copySheet()出异常问题解决了,并且,我可以按上面我的想法尝试用jxl能否对带宏(macro)的sheet进行copy,以下是具体实现代码:
package test_JXL;

import java.io.File;
import jxl.Sheet;
import jxl.Workbook;
import jxl.WorkbookSettings;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;

public class Test_JXL_copysheet {
	
	File to_file,from_file;
	
	public Test_JXL_copysheet(String from_filename, String to_filename) {
		to_file = new File(to_filename);
		from_file = new File(from_filename);
		try {
			WritableWorkbook to_wwb; //创建可写入workbook对象
			if(!this.to_file.exists()) {//如果该文件不存在,则先创建一个wwb				
				to_wwb = Workbook.createWorkbook(this.to_file);
			} else {//如果该文件已经存在,则应该是获取该workbook,并update其
				Workbook rw = jxl.Workbook.getWorkbook(this.to_file);
				to_wwb = Workbook.createWorkbook(this.to_file, rw);
			}
			
			WritableSheet ws = to_wwb.createSheet("Product Tree", to_wwb.getNumberOfSheets()); //创建工作表1 -- Tree型文件
			
			jxl.write.Label label = new jxl.write.Label(0, 0, "This is Sheet 1"); //写excel单元格数据
			ws.addCell(label);
			
			//--------testing...------------------------
			WorkbookSettings newSettings = new WorkbookSettings();
			newSettings.setPropertySets(true);

			Workbook from_rw = jxl.Workbook.getWorkbook(this.from_file, newSettings);
			Sheet from_sheet1 = from_rw.getSheet(0);
			Sheet from_sheet2 = from_rw.getSheet(1);
			WritableWorkbook from_wwb = Workbook.createWorkbook(this.from_file, from_rw, newSettings);
			
			from_wwb.copySheet(1, "yes", 2);
			
			to_wwb.copySheet("Product Tree", "copy", 1);
			to_wwb.importSheet("YES", 2, from_sheet1);			
			to_wwb.importSheet("hao", 3, from_sheet2);
			
			
			//写入到Exel工作表中
			to_wwb.write();
			from_wwb.write();
			//关闭Excel工作薄对象
			to_wwb.close();
			from_rw.close();
			from_wwb.close();
		}catch (Exception e) {
			e.printStackTrace();
			System.err.println("There is an error!\n");
		}
	}
	
	public static void main(String[] args) {
		new Test_JXL_copysheet("d:\\FAP1301578_4_Item_Upload.xls", "d:\\test.xls");
	}
	
}


程序大概是这样:
其中"d:\\FAP1301578_4_Item_Upload.xls"是一个带宏的excel文件,而 "d:\\test.xls" 是想要把带宏的excel文件中的表单拷贝到这个文件的目的文件。
然后我就设置了一下setPropertySets属性,然后调用了copySheet()和importSheet()进行了复制和导入,其中importSheet()是从另一个workbook中深拷贝一个sheet。

程序运行结果是,可以正常运行,拷贝也成功,但是宏好像失效了
于是,我想到了另外一种方法,避开这个问题:
先将我们要拷贝的excel文件以字节流的形式拷贝一份,然后打开那个带有宏的sheet,因为我不需要对宏做什么修改,只是在这个带宏的表单上修改一些字符,比如在指定Cell中写入一些字符等,这时只需要正常的用jxl的addCell()即可,写完后再保存,ok!
这样我们就实现了一个拷贝了带宏的excel文件,并在相关sheet上进行了更新!
代码修改如下:
... ...
//--------testing...------------------------
			WorkbookSettings newSettings = new WorkbookSettings();
			newSettings.setPropertySets(true);

			Workbook from_rw = jxl.Workbook.getWorkbook(this.from_file, newSettings);
			Sheet from_sheet1 = from_rw.getSheet(0);
			Sheet from_sheet2 = from_rw.getSheet(1);
			WritableWorkbook from_wwb = Workbook.createWorkbook(this.from_file, from_rw, newSettings);

			WritableSheet from_ws = from_wwb.getSheet(1); //修改部分			

			label = new jxl.write.Label(1, 1, "This has been changed!"); //写excel单元格数据  修改部分
			from_ws.addCell(label);//修改部分

			
			to_wwb.copySheet("Product Tree", "copy", 1);
			to_wwb.importSheet("YES", 2, from_sheet1);			
			to_wwb.importSheet("hao", 3, from_sheet2);
			
			
			//写入到Exel工作表中
			to_wwb.write();
			from_wwb.write();
			//关闭Excel工作薄对象
			to_wwb.close();
			from_rw.close();
			from_wwb.close();
... ...

猜你喜欢

转载自guhanjie.iteye.com/blog/1679934
jxl