作者John Zukowski 翻译Roger Sun 原文来源 # 译文地址 bin/forum/topiccgi?forum=&topic= ============================================== JAR文件是打包基于JAVA技术的解决方案的标准方法它允许开发者将所有相关内容(class图片声音及所有支持的文件)打包到一个文件中JAR格式支持压缩认证版本号及其他很多特性 从JAR文件中读取文件是很麻烦的事情但是也不一定全是这样本文将告诉你如何从JAR文件中读取文件首先得到JAR文件中的文件目录然后在进行具体的某一个文件的操作 如果你对于常用的ZIP格式比较熟悉的话JAR文件也就差不多JAR文件提供一种将多个文件打包到一个文件中的方法其中每一个文件可能独立地被压缩JAR文件所增加的内容是manifest它允许开发者可以提供附加的关于内容的信息例如manifest表明JAR文件中的哪个文件是用来运行一个程序的或者库的版本号等 JSEDK提供了一个jar工具你可以用它从控制台读写JAR文件然而如果你需要在程序中代码读写JAR文件可能需要一点时间(本文只包含如何在程序中读写JAR文件)好消息是你可以做到这一点而且你不用担心解压的事因为类库将帮助你完成这些你所需要的类文件位于javautiljar包中这里主要的类是JarFile它是jar文件自身的一个引用较大文件中的每一个单独的文件是通过一个JarEntry引用的 首先通过把将JAR文件位置传给构造函数创建一个JarFile的实例位置可能是String或File的形式如下 JarFile jarFile = new JarFile(thefilejar); 或者 File file = new File(thefilejar); JarFile jarFile = new JarFile(file); 你可能注意到当文件不在class path中时JarFile类对于从JAR中读取文件文件是很有用的 当你想指定目标JAR文件时JarFile类对于从JAR中读取文件同样也很有用当然如果JAR文件在class path中从其中读取文件的方法比较简单你可以用下面的方法 URL url = ClassLoadergetSystemResource(name); 或者 InputStream stream = ClassLoadergetSystemResourceAsStream(name); 这种技术允许你从在class path中的JAR文件里读取文件你不必指定JAR文件名 还有其他的构造函数如认证支持标志要删除的文件等这些构造函数在这儿不做说明 当你有了该JAR文件的一个引用之后你就可以读取其文件内容中的目录信息了JarFile的entries方法返回所有entries的枚举集合(Enumeration)通过每一个entry你可以从它的manifest文件得到它的属性任何认证信息以及其他任何该entry的信息如它的名字或者大小等 Enumeration enum = jarFileentries(); while (enumhasMoreElements()) { process(enumnextElement()); } 正如前面提到的每一个entry是一个JarEntry该类有getNamegetSizegetCompressedSize等方法 下面让我们举例说明在程序中如何使用这些特性下面的程序显示你指定的JAR文件中内容的名称大小压缩大小等(这有点类似于在使用jar命令时指定t和v选项) import javaio*; import javautil*; import javautiljar*; public class JarDir { public static void main (String args[]) throws IOException { if (argslength != ) { Systemoutprintln( Please provide a JAR filename); Systemexit(); } JarFile jarFile = new JarFile(args[]); Enumeration enum = jarFileentries(); while (enumhasMoreElements()) { process(enumnextElement()); } } private static void process(Object obj) { JarEntry entry = (JarEntry)obj; String name = entrygetName(); long size = entrygetSize(); long compressedSize = entrygetCompressedSize(); Systemoutprintln( name + \t + size + \t + compressedSize); } } 如果你用JSE中的jcejar作为参数运行上面的JarDir程序你将看到类似于下面的输出(部分为省略掉的输出) METAINF/MANIFESTMF METAINF/JCEJARSSF METAINF/JCEJARSDSA METAINF/ javax/ javax/crypto/ javax/crypto/interfaces/ javax/crypto/interfaces/DHKeyclass javax/crypto/interfaces/DHPublicKeyclass javax/crypto/interfaces/DHPrivateKeyclass javax/crypto/interfaces/PBEKeyclass javax/crypto/SecretKeyclass 注意输出最开始的METAINF行这是manifest和安全认证信息字节的entries不是文件但是有点相当于目录 为了从JAR文件中真正读取一个指定的文件你必须到其entry的InputStream这和JarEntry不一样这是因为JarEntry只是包含该entry的有关信息但是并不实际包含该entry的内容这和File和FileInputStream的区别有点儿相似访问文件没有打开文件它只是从目录中读取了该文件的信息下面是如何得到entry的InputStream InputStream input = jarFilegetInputStream(entry); 当你有了输入流你就可以像读取其他流一样读取它在文本流中(text stream)记得使用读取器(Reader)从流中取得字符对于面向字节的流如图片文件直接读取就行了 下面的程序演示如何从JAR文件中读取文件指定JAR文件的名称要读取的文件的名称(打包JAR文件中的某一个文件)作为参数来调用该程序要读取的文件应该有一个文本类型的 import javaio*; import javautiljar*; public class JarRead { public static void main (String args[]) throws IOException { if (argslength != ) { Systemoutprintln( Please provide a JAR filename and file to read); Systemexit(); } JarFile jarFile = new JarFile(args[]); JarEntry entry = jarFilegetJarEntry(args[]); InputStream input = jarFilegetInputStream(entry); process(input); jarFileclose(); } private static void process(InputStream input) throws IOException { InputStreamReader isr = new InputStreamReader(input); BufferedReader reader = new BufferedReader(isr); String line; while ((line = readerreadLine()) != null) { Systemoutprintln(line); } readerclose(); } } 假设在myfilesjar文件中有一个spidertxt文件spider文件的内容如下 The itsy bitsy spider Ran up the water spout Down came the rain and Washed the spider out 你可以通过下面的命令来显示该文本文件的内容 java JarRead myfilesjar spidertxt 有关JAR文件的更多内容请参考JAR文件规范 |