【问题标题】:Using Java to read a .jar manifest file使用 Java 读取 .jar 清单文件
【发布时间】:2013-10-21 05:46:13
【问题描述】:

所以我试图通过检查 mainfest 文件中的一些值来查看 .jar 是否有效。使用java读取和解析文件的最佳方法是什么?我想用这个命令来提取文件

jar -xvf anyjar.jar META-INF/MANIFEST.MF

但是我可以这样做吗:

File manifest = Command.exec("jar -xvf anyjar.jar META-INF/MAINFEST.MF");

然后使用一些缓冲阅读器或其他东西来解析文件的行?

感谢您的帮助...

【问题讨论】:

标签: java jar manifest


【解决方案1】:

使用jar 工具的问题在于它需要安装完整的JDK。许多Java用户只会安装JRE,不包括jar

另外,jar 必须在用户的 PATH 上。

因此,我建议使用适当的 API,如下所示:

Manifest m = new JarFile("anyjar.jar").getManifest();

这实际上应该更容易!

【讨论】:

  • 哦,哇,这确实更有意义。等等,我也在使用 Command.exec(“提取 jar 的代码”)。有没有更简单的方法来做到这一点。
  • 是的。但是在 Stackoverflow 上肯定已经有一个问题了。
  • 到目前为止,我已经能够找到正在使用命令提示符但此链接似乎可以工作,但它看起来有点复杂哈哈。为什么不能像 jarfile.run() 之类的那样简单。 programcreek.com/2012/08/unzip-a-jar-file-in-java-program
  • 是的,不幸的是它更复杂。但是你可以直接复制粘贴,谁在乎呢?
【解决方案2】:

java.lang.Package 中的Package 类有方法来做你想做的事。这是使用您的 java 代码获取清单内容的简单方法:

String t = this.getClass().getPackage().getImplementationTitle();
String v = this.getClass().getPackage().getImplementationVersion();

我把它放到一个共享实用程序类的静态方法中。该方法接受一个类句柄对象作为参数。这样,我们系统中的任何类都可以在需要时获取自己的清单信息。显然,可以轻松修改该方法以返回值的数组或哈希图。

调用方法:

    String ver = GeneralUtils.checkImplVersion(this);

GeneralUtils.java 文件中的方法:

public static String checkImplVersion(Object classHandle)
{
   String v = classHandle.getClass().getPackage().getImplementationVersion();
   return v;
}

并且要获得除了可以通过 Package 类获得的那些字段值以外的清单字段值(例如,您自己的 Build-Date),您需要获得主要属性并通过这些属性来处理,询问您想要的特定属性。下面的代码是我发现的一个类似问题的一个小修改,可能在 SO 上。 (我想记下它,但我把它弄丢了 - 抱歉。)

将 this 放入 try-catch 块中,将 classHandle(“this”或 MyClass.class )传递给方法。 "classHandle" 是 Class 类型:

  String buildDateToReturn = null;
  try
  {
     String path = classHandle.getProtectionDomain().getCodeSource().getLocation().getPath();
     JarFile jar = new JarFile(path);  // or can give a File handle
     Manifest mf = jar.getManifest();
     final Attributes mattr = mf.getMainAttributes();
     LOGGER.trace(" --- getBuildDate: "
           +"\n\t path:     "+ path
           +"\n\t jar:      "+ jar.getName()
           +"\n\t manifest: "+ mf.getClass().getSimpleName()
           );

     for (Object key : mattr.keySet()) 
     {
        String val = mattr.getValue((Name)key);
        if (key != null && (key.toString()).contains("Build-Date"))
        {
           buildDateToReturn = val;
        }
     }
  }
  catch (IOException e)
  { ... }

  return buildDateToReturn;

【讨论】:

  • 关于 Package 方法,这些方法必须在 Manifest 中使用正确的名称(例如“Implementation-Version”)进行定义,这些名称可在类 java.util.jar.Attributes 中找到。姓名。这不是特别有据可查的。
【解决方案3】:

最简单的方法是使用 JarURLConnection 类:

String className = getClass().getSimpleName() + ".class";
String classPath = getClass().getResource(className).toString();
if (!classPath.startsWith("jar")) {
    return DEFAULT_PROPERTY_VALUE;
}

URL url = new URL(classPath);
JarURLConnection jarConnection = (JarURLConnection) url.openConnection();
Manifest manifest = jarConnection.getManifest();
Attributes attributes = manifest.getMainAttributes();
return attributes.getValue(PROPERTY_NAME);

因为在某些情况下...class.getProtectionDomain().getCodeSource().getLocation(); 给出了vfs:/ 的路径,所以应该另外处理。

或者,使用 ProtectionDomain:

File file = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI());
if (file.isFile()) {
    JarFile jarFile = new JarFile(file);
    Manifest manifest = jarFile.getManifest();
    Attributes attributes = manifest.getMainAttributes();
    return attributes.getValue(PROPERTY_NAME);
}

【讨论】:

    猜你喜欢
    • 2014-05-13
    • 2013-06-14
    • 1970-01-01
    • 2011-08-22
    • 2011-04-16
    • 1970-01-01
    • 2013-05-28
    • 1970-01-01
    • 2016-03-22
    相关资源
    最近更新 更多