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

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

【问题讨论】:

    标签: java jar manifest.mf


    【解决方案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】:

      我根据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 上测试过。

      我希望这对其他人有用。

      【讨论】:

      • 唯一的问题是包含以下内容的行: 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 上的最新版本)。答案stackoverflow.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】:
          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);
                  }
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-10-27
            • 2017-01-26
            • 1970-01-01
            • 2015-03-25
            • 2012-11-22
            • 2012-09-27
            • 1970-01-01
            • 2010-09-29
            相关资源
            最近更新 更多