出现问题的流程大致是:读取一系列的excel文件的信息存入数据库后,先把文件拷贝到备份目录,再删除源excel文件,该项目原先开发和部署环境(j2sdk1.4.2_12+jboss-4.0.5.GA)使用正常,文件也能正常被移动到备份目录,后在另一客户那里实施,换成了jdk1.5,因此我就用jdk1.5编译了一遍,没问题了,就给客户安装演示系统,因为读取excel数据一直都正常(从所导出的报表可得知),所以刚开始几天也没怎么关心这些excel文件是否正常被移动.
发现问题后赶紧debug跟踪,设置断点进行一步步查看,执行完file.delete()语句后,excel又可以被删除了,然后取消断点再运行,我靠,执行完delete()语句后,excel原封不动的待在那里.因为原来系统是运行正常的,于是重新编译部署在jdk1.4+jboss4.0下,运行正常.
真是奇怪了,同样的代码怎么会不一样呢,于是网上搜索关键字("java+java.io.file.delete()"),发现再sun论坛上也有人提出同样的问题,就是删除不了,且无任何错误提示,和我的情况一样,不过他的是jdk1.4下,跟帖的人问他输入流是否确定都close了,或者同时有人在占用该资源的引用,并且建议使用System.gc(),不过问题也没什么解决.后来又看了其他帖子,没什么建设性,索性回到项目源代码上,这是删除文件语句前的读取excel部分代码.
- jxl.Workbook rwb = null;
- try{
- //构建Workbook对象, 只读Workbook对象
- //直接从本地文件创建Workbook
- //从输入流创建Workbook
- InputStream is = new FileInputStream(fileAllName);
- WorkbookSettings workbookSettings=new WorkbookSettings();
- //workbookSettings.setLocale(new Locale("zh","CN"));
- // workbookSettings.setEncoding("ISO-8859-1");
- workbookSettings.setEncoding("GBK");
- rwb = Workbook.getWorkbook(is,workbookSettings);
- //Sheet(术语:工作表)就是Excel表格左下角的Sheet1,Sheet2,Sheet3但在程序中
- //Sheet的下标是从0开始
- //获取第一张Sheet表
- Sheet rs = rwb.getSheet(0);
- //获取Sheet表中所包含的总列数
- int rsColumns = rs.getColumns();
- //获取Sheet表中所包含的总行数
- int rsRows = rs.getRows();
- ..............省略..........
- //读取行信息
- }catch(Exception e)
- {
- }
- finally{
- //操作完成时,关闭对象,释放占用的内存空间
- rwb.close();
- }
该代码在jdk1.4下运行正常,按道理该释放的都释放了,联想到搜索资料上多次提及的未释放资源,我把注意力放在了该段代码的7.InputStream is = new FileInputStream(fileAllName); 上,这个输入流却没有放进finally区,照此思路,我把代码改成了下面这个样子
- jxl.Workbook rwb = null;
- InputStream is = null;
- try{
- //构建Workbook对象, 只读Workbook对象
- //直接从本地文件创建Workbook
- //从输入流创建Workbook
- is = new FileInputStream(fileAllName);
- WorkbookSettings workbookSettings=new WorkbookSettings();
- //workbookSettings.setLocale(new Locale("zh","CN"));
- // workbookSettings.setEncoding("ISO-8859-1");
- workbookSettings.setEncoding("GBK");
- rwb = Workbook.getWorkbook(is,workbookSettings);
- //Sheet(术语:工作表)就是Excel表格左下角的Sheet1,Sheet2,Sheet3但在程序中
- //Sheet的下标是从0开始
- //获取第一张Sheet表
- Sheet rs = rwb.getSheet(0);
- //获取Sheet表中所包含的总列数
- int rsColumns = rs.getColumns();
- //获取Sheet表中所包含的总行数
- int rsRows = rs.getRows();
- ..............省略..........
- //读取行信息
- }catch(Exception e)
- }
- finally{
- //操作完成时,关闭对象,释放占用的内存空间
- rwb.close();
- try
- {
- is.close();
- }
- catch(Exception e){}
- }
也就是将is也显性的立即释放掉,在j2sdk1.5.0_13+jboss-4.2.0.GA上运行,excel被成功删除,后更新到客户演示环境,也成功了.
究其原因,我估计是jdk1.4和jdk1.5在垃圾回收策略上的不同,在jdk1.4上,is在rwb.close();后就被释放掉了,而在1.5上则有些延迟,这也能解释为何我在jdk1.5上设置断点进行单步跟踪(相当于sheep())的时候能删除,当然,原来代码本身写得也不规范,is应该要被显性释放.