现象:在RCP程序中,以相对路径读文件遇到以下异常。但用绝对路径则没有问题。
try {
FileInputStream fileStream = new FileInputStream("poc.xml");
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
java.io.FileNotFoundException: poc.xml (The system cannot find the file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at java.io.FileInputStream.<init>(Unknown Source)
at LoadFile.execute(LoadFile.java:30)
at org.eclipse.ui.internal.handlers.HandlerProxy.execute(HandlerProxy.java:293)
at org.eclipse.core.commands.Command.executeWithChecks(Command.java:476)
at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:508)
at org.eclipse.ui.internal.handlers.HandlerService.executeCommand(HandlerService.java:169)
at org.eclipse.ui.internal.handlers.SlaveHandlerService.executeCommand(SlaveHandlerService.java:241)
at org.eclipse.ui.menus.CommandContributionItem.handleWidgetSelection(CommandContributionItem.java:829)
at org.eclipse.ui.menus.CommandContributionItem.access$19(CommandContributionItem.java:815)
at org.eclipse.ui.menus.CommandContributionItem$5.handleEvent(CommandContributionItem.java:805)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1053)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:4165)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3754)
at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2696)
at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2660)
at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2494)
at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:674)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:667)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
at testsample.Application.start(Application.java:20)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:344)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:622)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:577)
at org.eclipse.equinox.launcher.Main.run(Main.java:1410)
at org.eclipse.equinox.launcher.Main.main(Main.java:1386)
原因:在网上找了很久,一直怀疑是RCP程序的配置问题。后来发现,原因是因为RCP程序的ClassLoader与系统的ClassLoader不一致造成的。原理有点复杂,我也不是什么明白。反正在RCP程序中,相对路径的文件必须用RCP程序自身的ClassLoader去加载,而不能使用一般的java程序所惯用的入口程序的ClassLoader(也就是main方法所在的平台class)。
解决:
方法一:
Class.getClassLoader().getResource(name);
//或者
Class().getClassLoader().getResourceAsStream(name);
方法二:
如果你必须用到File,那可以参考下面的代码,但前提是你已经为你的Project建立了Product
Bundle bundle = Platform.getProduct().getDefiningBundle();
URL fileURL = bundle.getEntry(path);
File file = null;
try {
file = new File(FileLocator.resolve(fileURL).toURI());
} catch (URISyntaxException e1) {
e1.printStackTrace();
return;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
参考转换中值:
path:data/testcase/
fileURL:bundleentry://30.fwk648734830/data/testcase/
FileLoactor.resove(fileURL):file:/D:/Project/autotester-I20110901/data/testcase/
file.path:D:\Project\autotester-I20110901\data\testcase
用getClass().openResourceAsSteam(path)和用bundle.getEntry(path)的path是不一样的,前者的当前路径是class/classDir(Project/conf/),后者的当前路径是project(Project/)。即,如果你的文件路径为是放在Project/config/a.xml,而config加入classpath中,那么方法一的要传入"a.xml",而方法二要传入“config/a.xml”。