使用 JAVA 从 jar 文件中读取 MANIFEST.MF 文件

Posted

技术标签:

【中文标题】使用 JAVA 从 jar 文件中读取 MANIFEST.MF 文件【英文标题】:reading MANIFEST.MF file from jar file using JAVA 【发布时间】:2011-04-16 04:16:28 【问题描述】:

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

【问题讨论】:

【参考方案1】:

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

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

异常处理留给你 :)

【讨论】:

【参考方案2】:

我建议如下:

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

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

【讨论】:

这是我需要的东西(阅读Implementation-Version)。可悲的是,尽管清单在“META-INF/MANIFEST.MF”中,但这对我来说在解压类中不起作用。 这在默认情况下不起作用,除非您为 maven-jar-plugin 添加 addDefaultImplementationEntries 为 true 以便它实际上包含版本信息。默认情况下,清单文件不包含任何内容。另外@Victor,尝试运行 mvn package 并查看内部是否有正确的信息。一般那些版本配置在maven-jar-plugin或者maven-war-plugin,所以未打包的类没有。【参考方案3】:

你可以使用这样的东西:

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。

【讨论】:

非常好,这通过了所有清单。 我在使用此代码时弄错了清单。例如:Main-Class:org.GNOME.Accessibility.AtkWrapper。但事实并非如此。奇怪。【参考方案4】:

我根据***的一些想法实现了一个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 上测试过。

我希望这对其他人有用。

【讨论】:

唯一的问题是包含以下内容的行: String manifestPath = StringUtils.join[...] Using File.separatorChar 似乎在 Windows 下生成了一个无效的 URL ...可能最好使用 "/ " 代替。 这对我有用,但后来我发现 stviper 的答案也有效,而且简单得多。【参考方案5】:

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

    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;

【讨论】:

【参考方案6】:

您可以使用来自jcabi-manifests 的实用程序类Manifests

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

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

【讨论】:

这很棒而且效果很好。很高兴它是一个图书馆。如果所有清单都被阅读,那会更好。我注意到 Javadoc 有一个 entry(),这可能是我建议的,但是该方法没有出现在我正在使用的版本中(1.1 - MvnRepository 上的最新版本)。答案***.com/a/3777116/1019307 具有检索所有清单的解决方案。【参考方案7】:

保持简单。 JAR 也是 ZIP,所以任何 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();

尽管有灵活性,但对于仅读取数据this 的答案是最好的。

【讨论】:

【参考方案8】:
    阅读版本; 我们将 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);
        
    

【讨论】:

以上是关于使用 JAVA 从 jar 文件中读取 MANIFEST.MF 文件的主要内容,如果未能解决你的问题,请参考以下文章

Java InputStream 无法从 JAR 中读取文件

如何从 Java jar 文件中读取资源文件?

如何从 Java jar 文件中读取资源文件?

如何从Java jar文件中读取资源文件?

怎样从JAR文件中读取文件?

怎么从外部读取jar包中的资源文件