定位文件
在不同平台之间移植 Java 应用程序时的另一个常见问题是对文件进行定位。不同的环境中有不同的文件定位方法。
在本场景中,假设您希望定位某个实用程序 Java 项目中的一个 DTD 文件,该文件被某个企业应用程序项目中的一个 Web 项目使用。若要定位 WebSphere® Studio Application Developer (Application Developer) V5.1.2 中的 DtdEntityResolver 类中的 sample.dtd 文件,您可以编写清单 2 中的代码,它将获得类似于 E:/workspace/UtilProj/bin/com/ibm/util/sample.dtd 的路径。
清单 2. 用于定位文件的示例代码
Class clazz = getClass();
URL url = clazz.getResource("."); //Trying to get the URL of current directory
String currentPath = url.getPath();
String filePath = currentPath + "sample.dtd";
查看此代码之后,您可能会说,这非常好,我拥有了一个更好的解决方案。的确存在一个更好的解决方案,但是让我们首先使用此代码,它在 Application Developer V5.1.2 的 WebSphere Test Environment 中工作得非常好。通过这种方式,您对该文件进行了定位。
在完成所有其他模块以后,您的团队决定将该企业应用程序项目部署到生产环境——运行于 AIX 之上的 WebSphere Application Server (Application Server) V5.1。这次,您没那么幸运了。代码引发了 java.lang.NullPointerException 并且您定位文件失败。
陷阱
为什么会发生这种情况呢?它在 Windows 上工作得非常好,但是在 AIX 上却失败了。这是否是 Java 代码的跨平台错误?起初您可能会这样认为。然而,情况并非如此。让我们再次查看上述代码所产生的文件路径。它是 $Workspace/$ProjectName/$bin/$packageName/sample.dtd。您的项目主目录中有一个 bin 目录,该目录用于存储编译后的二进制类。当您在运行于 AIX 上的 Application Server 中部署企业存档(Enterprise Archive,EAR)文件之后,是否还存在一个 bin 目录呢?正如您所知道的,在将企业项目导出为 EAR 之后,实用程序 Java 项目将包括在一个 Java 存档(Java Archive,JAR)文件中。在 JAR 文件中,您无法使用“.”(当前目录指示符)来定位资源,因此 java.lang.Class.getResource(".") 返回一个 Null 对象。
弄清这一点之后,对于运行在 Windows 平台上的独立 Application Server,您可能认为上述代码可能也会引发同样的 NullPointerException。当将相同的 EAR 部署在独立 Application Server 而不是内置 WebSphere Test Environment 中时,将会发生同样的错误。您的代码在 Application Developer V5.1.2 附带的测试环境中和在 Application Server 5.1.x 中具有不同的行为(即使两者都运行在同样的 Windows 平台上),这听起来非常奇怪。对于企业应用程序项目中的 Java 项目,WTE 直接从您工作区中的 bin 目录加载二进制类,而独立应用程序服务器则从已部署的 JAR 文件加载它们。如果您对两个环境之间的比较很感兴趣,请参见 Rational® Application Developer 信息中心(请参见参考资料)。有关 WebSphere Test Environment 的更多详细信息可以在 WebSphere Application Server Test Environment Guide 中找到(请参见参考资料)。
在 Rational Application Developer V6.0 中,该测试环境旨在作为一个独立应用程序服务器,因此作为测试环境的 Application Server 和作为独立服务器的 Application Server 之间的差异不复存在。上述代码在 Rational Application Developer V6.0 和在独立 Application Server 6 上具有相同的行为,无论是在 Windows 还是在 AIX 上。NullPointerException 始终会被引发,因为两个环境都将企业应用程序项目中的实用程序 Java 项目视为一个 JAR 文件。
解决办法
既然您知道了为什么会出错,下面就让我们了解一下更好的解决方案:使用 getClass().getResource("sample.dtd")。这里,java.lang.Class.getResource(String filename) 将资源查找任务委托给关联的 ClassLoader。无论文件是在 JAR 中还是在 bin 目录中,它都始终返回解析后的文件路径。图 1 显示了 Windows 和 AIX 平台上不同运行时环境之间的比较。
请注意,在下面的图 1 中,java.lang.Class.getResource(String filename) 在每种环境中都可以正常工作,无论是内置的 Application Developer 测试环境、运行在 Windows 上的独立应用程序服务器还是运行在 AIX 上的独立应用程序服务器。结论是,java.lang.Class.getResource(String filename) 始终是确保平台可移植性的首选方法。
图 1. getResource(fileName) 在 Windows 和 AIX 上的结果
提醒
JAR 文件被打包为 ZIP 文件格式,因此您可以将它们用于类 ZIP 任务,例如无损数据压缩、归档、解压缩和存档解包。在您使用 getClass().getResource(String filename) 来定位文件 URL(比如 $INSTALLEDAPP_HOME/SampleEAR.ear/UtilProj.jar!/com/ibm/util/sample.dtd)以后,下一个任务是读取 JAR 文件中的内容;请参见清单 3。
清单 3. 读取 JAR 文件内容的错误方法
URL jarUrl = getClass().getResource(“simple.dtd");
String path = fileUrl.getPath();
FileInputStream fis = new FileInputStream(path);
读取 JAR 文件中的内容是相当棘手的。清单 3 显示了一种获得文件 simple.dtd 的 FileInputStream 的直观方法,但是它无效。此方法会引发 Java.io.FileNotFoundException。请参见清单 4 和清单 5 以获得正确的方法。
清单 4. 读取 JAR 文件内容的正确方法
URL jarUrl = getClass().getResource(“simple.dtd");
URLConnection urlConn = jarUrl.openConnection();
InputStream is = urlConn.getInputStream();
清单 5. 读取 JAR 文件内容的正确方法
InputStream is = getClass().getResourceAsInputStream("simple.dtd");
为什么 new FileInputStream(String name) 无效而 URL.openConnection().getInputStream() 却有效呢?因为 java.net.URL 的每个实例都与某种协议关联,例如 HTTP、JAR、文件,等等。而且,每种协议都具有特定的处理程序(此处理程序是 java.net.URLStreamHandler 的实例),以处理相关协议的连接详细信息。URL.openConnection() 调用 URLStreamHandler.openConnection() 来获得 URLConnection 对象,此对象表示到该 URL 所引用的远程对象的连接。对于 HTTP 协议,将会返回一个 HttpURLConnection 对象;对于 JAR 协议,将会返回一个 JarURLConnection 对象。
对于清单 4 中的代码,urlConn 是 JarURLConnection 的一个实例。在调用 JarURLConnection 的 getInputStream 时,它调用 JarFile.getInputStream(JarEntry jarEntry) 和 jarEntry,在您的例子中是名为 simple.dtd 的文件。最后返回一个 JarInputStream 实例,用于读取 JAR 文件中的内容。
FileInputStream 无法正确工作的原因可能非常明显——JAR 文件中的 JarEntry 使用 Jar 协议。FileInputStream 仅处理文件协议,因此它自然无法成功处理 sample.dtd(JAR 文件中使用 JAR 协议的 JarEntry)。
对于清单 5 中的代码,getClass() 返回的类 literal 调用 ClassLoader.getResourceAsInputStream()。后者又调用 getResource(fileName).openConnection().getInputStream()。清单 5 中的代码在功能上等效于清单 4 中的代码。
总而言之,在读取 JAR 文件中的内容时,应该使用清单 4 或清单 5 中的代码;决不要使用 FileInputStream,因为它无法处理 JAR 协议。
分享到:
相关推荐
DB2从windowsXP迁移至AIX完整过程
将经分A库的Oracle RAC 从HPUX平台迁移到IBM AIX 平台。目前经分A库Oracle RAC 建立在基于Symantec SFCFS的四台HP节点系统上,数据文件建立在VXVM 的裸设备上,数据库容量110TB 。 由于Symantec VXVM采用的是跨...
- 迁移环境搭建 搭建用于应用迁移的开发环境和测试实验环境。 - 服务中间件和资源迁移 在应用代码迁移之前,首先完成应用运行所依赖的服务中间件和基础软件资源的迁移和转换。
DB2从AIX+server上转移(迁移)到linux上.docx
window tomcat项目迁移到linux上环境的配置及迁移过程中遇到问题的总结.
AIX LV迁移: 一、在同一卷组中操作,迁移L V 二、在不同一卷组中操作,迁移L V 建议在实施前做好数据备份,在业务不繁忙时停止应用操作
利用xtts跨平台增量传输表空间技术,轻松快速将aix环境下的oracle11g在1小时内迁移到linux环境下。 本次采用手动xtts的方式,该方法适用任意平台之间,源端>=oracle10.2.0.3,目标端>=11.2.0.4,包括windows<->linux...
AIX6.1系统安装详细过程、还有迁移的的内容、主要是安装的中的一些指令
LV-AIX镜像迁移.pdf
【TTS】AIX平台数据库迁移到Linux环境(真实环境).pdf【TTS】AIX平台数据库迁移到Linux环境(真实环境).pdf
AIX数据迁移
在Java EE / Hibernate应用程序中使用运行数据库迁移的示例项目。 设置 使用docker启动数据库的空实例: docker run -p5432:5432 --name postgres postgres 使用运行应用程序: java -jar payara-micro-5.181.jar ...
《决战Nginx技术卷:高性能Web服务器部署与运维(基于php、Java、...对于ASP.NET的用户来说,现在从Windows系统下向Linux系统迁移的用户很多,这就无疑会使用Mono,在本书中同样能够找到Mono的使用和迁移的解决方案。
基于Java的数据迁移工具,跨平台,跨数据库 该应用程序已经过mysql和oracle的测试,理论上也支持sqlserver,db2或其他数据库,但是我没有足够的时间在所有平台/数据库中对其进行测试,因此,如果您使用此工具,请...
毕设项目-基于迁移学习flask的web端三维模型重建系统源码.zip毕设项目-基于迁移学习flask的web端三维模型重建系统源码.zip毕设项目-基于迁移学习flask的web端三维模型重建系统源码.zip毕设项目-基于迁移学习flask的...
项目名称:基于Flask框架的实验楼Web应用 - Flask_syl 开发语言:Python 项目构成:本项目共包含102个文件,具体分布如下: - Python源文件 (.py):47个 - Python字节码文件 (.pyc):42个(由源文件编译生成,...
技术文章(迁移问题解决方案)-从WebLogic 6_1迁移到 WebLogic 8_1.mht
AIX系统LVM存储迁移手册
AIX7.1安装与迁移2014 不错的资源, 值得下载!
基于windows server 2012共享文件夹的Hyper-V实时迁移之二文件服务器及迁移用虚拟机的创建