使用 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 文件的主要内容,如果未能解决你的问题,请参考以下文章