35

有什么办法可以读取 jar 文件的内容。就像我想阅读清单文件以找到 jar 文件和版本的创建者一样。有没有办法达到同样的效果。

4

8 回答 8

52

下一个代码应该会有所帮助:

JarInputStream jarStream = new JarInputStream(stream);
Manifest mf = jarStream.getManifest();

异常处理留给你:)

于 2010-09-23T09:46:10.137 回答
44

我建议进行以下操作:

Package aPackage = MyClassName.class.getPackage();
String implementationVersion = aPackage.getImplementationVersion();
String implementationVendor = aPackage.getImplementationVendor();

其中 MyClassName 可以是您编写的应用程序中的任何类。

于 2013-09-11T12:49:23.267 回答
41

你可以使用这样的东西:

public static String getManifestInfo() {
    Enumeration resEnum;
    try {
        resEnum = Thread.currentThread().getContextClassLoader().getResources(JarFile.MANIFEST_NAME);
        while (resEnum.hasMoreElements()) {
            try {
                URL url = (URL)resEnum.nextElement();
                InputStream is = url.openStream();
                if (is != null) {
                    Manifest manifest = new Manifest(is);
                    Attributes mainAttribs = manifest.getMainAttributes();
                    String version = mainAttribs.getValue("Implementation-Version");
                    if(version != null) {
                        return version;
                    }
                }
            }
            catch (Exception e) {
                // Silently ignore wrong manifests on classpath?
            }
        }
    } catch (IOException e1) {
        // Silently ignore wrong manifests on classpath?
    }
    return null; 
}

要获取清单属性,您可以遍历变量“mainAttribs”,或者如果您知道密钥,则直接检索所需的属性。

此代码循环遍历类路径上的每个 jar 并读取每个 MANIFEST。如果您知道 jar 的名称,您可能只想查看包含()您感兴趣的 jar 名称的 URL。

于 2010-09-23T09:46:05.150 回答
12

我根据stackoverflow的一些想法实现了一个AppVersion类,这里我只是分享整个类:

import java.io.File;
import java.net.URL;
import java.util.jar.Attributes;
import java.util.jar.Manifest;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AppVersion {
  private static final Logger log = LoggerFactory.getLogger(AppVersion.class);

  private static String version;

  public static String get() {
    if (StringUtils.isBlank(version)) {
      Class<?> clazz = AppVersion.class;
      String className = clazz.getSimpleName() + ".class";
      String classPath = clazz.getResource(className).toString();
      if (!classPath.startsWith("jar")) {
        // Class not from JAR
        String relativePath = clazz.getName().replace('.', File.separatorChar) + ".class";
        String classFolder = classPath.substring(0, classPath.length() - relativePath.length() - 1);
        String manifestPath = classFolder + "/META-INF/MANIFEST.MF";
        log.debug("manifestPath={}", manifestPath);
        version = readVersionFrom(manifestPath);
      } else {
        String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF";
        log.debug("manifestPath={}", manifestPath);
        version = readVersionFrom(manifestPath);
      }
    }
    return version;
  }

  private static String readVersionFrom(String manifestPath) {
    Manifest manifest = null;
    try {
      manifest = new Manifest(new URL(manifestPath).openStream());
      Attributes attrs = manifest.getMainAttributes();

      String implementationVersion = attrs.getValue("Implementation-Version");
      implementationVersion = StringUtils.replace(implementationVersion, "-SNAPSHOT", "");
      log.debug("Read Implementation-Version: {}", implementationVersion);

      String implementationBuild = attrs.getValue("Implementation-Build");
      log.debug("Read Implementation-Build: {}", implementationBuild);

      String version = implementationVersion;
      if (StringUtils.isNotBlank(implementationBuild)) {
        version = StringUtils.join(new String[] { implementationVersion, implementationBuild }, '.');
      }
      return version;
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
    return StringUtils.EMPTY;
  }
}

基本上,这个类可以从它自己的 JAR 文件的清单或它的类文件夹中的清单中读取版本信息。希望它可以在不同的平台上运行,但到目前为止我只在 Mac OS X 上测试过它。

我希望这对其他人有用。

于 2013-07-24T07:46:48.500 回答
4

用这种简单的方式实现属性

    public static String  getMainClasFromJarFile(String jarFilePath) throws Exception{
    // Path example: "C:\\Users\\GIGABYTE\\.m2\\repository\\domolin\\DeviceTest\\1.0-SNAPSHOT\\DeviceTest-1.0-SNAPSHOT.jar";
    JarInputStream jarStream = new JarInputStream(new FileInputStream(jarFilePath));
    Manifest mf = jarStream.getManifest();
    Attributes attributes = mf.getMainAttributes();
    // Manifest-Version: 1.0
    // Built-By: GIGABYTE
    // Created-By: Apache Maven 3.0.5
    // Build-Jdk: 1.8.0_144
    // Main-Class: domolin.devicetest.DeviceTest
    String mainClass = attributes.getValue("Main-Class");
    //String mainClass = attributes.getValue("Created-By");
    //  Output: domolin.devicetest.DeviceTest
    return mainClass;
}
于 2019-02-03T12:39:56.873 回答
3

您可以使用jcabi-manifestsManifests中的实用程序类:

final String value = Manifests.read("My-Version");

该类将MANIFEST.MF在类路径中找到所有可用文件,并从其中一个文件中读取您要查找的属性。另外,请阅读:http ://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html

于 2012-12-30T08:56:22.543 回答
1

把事情简单化。AJAR也是 aZIP所以任何ZIP代码都可以用来读取MAINFEST.MF

public static String readManifest(String sourceJARFile) throws IOException
{
    ZipFile zipFile = new ZipFile(sourceJARFile);
    Enumeration entries = zipFile.entries();

    while (entries.hasMoreElements())
    {
        ZipEntry zipEntry = (ZipEntry) entries.nextElement();
        if (zipEntry.getName().equals("META-INF/MANIFEST.MF"))
        {
            return toString(zipFile.getInputStream(zipEntry));
        }
    }

    throw new IllegalStateException("Manifest not found");
}

private static String toString(InputStream inputStream) throws IOException
{
    StringBuilder stringBuilder = new StringBuilder();
    try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)))
    {
        String line;
        while ((line = bufferedReader.readLine()) != null)
        {
            stringBuilder.append(line);
            stringBuilder.append(System.lineSeparator());
        }
    }

    return stringBuilder.toString().trim() + System.lineSeparator();
}

尽管具有灵活性,但对于仅读取数据来说,这个答案是最好的。

于 2017-12-18T18:17:39.337 回答
1
  1. 阅读版本;
  2. 我们将 MANIFEST.MF 从 jar 复制到用户主页。
    public void processManifestFile() {
        String version = this.getClass().getPackage().getImplementationVersion();
        LOG.info("Version: {}", version);
        Path targetFile = Paths.get(System.getProperty("user.home"), "my-project", "MANIFEST.MF");

        try {
            URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation();
            JarFile jarFile = new JarFile(url.getFile());
            Manifest manifest = jarFile.getManifest();
            try(FileWriter fw = new FileWriter(targetFile.toFile())) {
                manifest.getMainAttributes().entrySet().stream().forEach( x -> {
                    try {
                        fw.write(x.getKey() + ": " + x.getValue() + "\n");
                        LOG.info("{}: {}", x.getKey(), x.getValue());
                    } catch (IOException e) {
                        LOG.error("error in write manifest, {}", e.getMessage());
                    }
                });
            }
            LOG.info("Copy MANIFEST.MF to {}", targetFile);
        } catch (Exception e) {
            LOG.error("Error in processing MANIFEST.MF file", e);
        }
    }
于 2020-07-02T06:56:28.420 回答