чтение манифеста.MF-файл из jar-файла с использованием JAVA

есть ли способ прочитать содержимое файла jar. как я хочу прочитать файл манифеста, чтобы найти создателя файла jar и версии. Есть ли способ достичь того же?

6 ответов


следующий код должен помочь:

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

обработка исключений остается для вас :)


вы можете использовать что-то вроде этого:

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 на пути к классам и считывает манифест каждого. Если вы знаете имя банки, вы можете посмотреть только URL-адрес, если он содержит () имя интересующей вас банки.


Я бы предложил сделать следующее:

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

где MyClassName может быть любым классом из вашего приложения, написанного вами.


я реализовал класс AppVersion в соответствии с некоторыми идеями из stackoverflow, здесь я просто разделяю весь класс:

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 или манифеста в его папке classes. И, надеюсь, он работает на разных платформах, но я тестировал его только на Mac OS X до сих пор.

Я надеюсь, что это будет полезно для кого-то еще.


вы можете использовать вспомогательный класс Manifests С jcabi-манифесты:

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

класс найдет все MANIFEST.MF файлы, доступные в classpath, и прочитайте атрибут, который вы ищете, из одного из них. Кроме того, прочитайте это: http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html


сохранить его простым. А 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();
}

несмотря на гибкость, для просто чтения данных этой ответ является лучшим.