Does anybody know how got get the version info for a executable/file via Java. The scenario is that I have a file on my local system and if the version on the server is newer then the one on my system I need to download the file from the server.
问题:
回答1:
After spending hours online and coding I found a solution using JNA to get the Version Information for a file.
import com.sun.jna.Library;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.win32.W32APIOptions;
import java.io.IOException;
public class FileVersionInfo
{
interface Version extends Library {
Version INSTANCE = (Version) Native.loadLibrary("Version", Version.class, W32APIOptions.UNICODE_OPTIONS);
public int GetFileVersionInfoSizeW(String lptstrFilename, int dwDummy);
public boolean GetFileVersionInfoW(String lptstrFilename, int dwHandle,
int dwLen, Pointer lpData);
public int VerQueryValueW(Pointer pBlock, String lpSubBlock,
PointerByReference lplpBuffer, IntByReference puLen);
}
static class VS_FIXEDFILEINFO extends com.sun.jna.Structure {
public int dwSignature;
public int dwStrucVersion;
public int dwFileVersionMS;
public int dwFileVersionLS;
public int dwProductVersionMS;
public int dwProductVersionLS;
public int dwFileFlagsMask;
public int dwFileFlags;
public int dwFileOS;
public int dwFileType;
public int dwFileSubtype;
public int dwFileDateMS;
public int dwFileDateLS;
public VS_FIXEDFILEINFO(com.sun.jna.Pointer p){
super(p);
}
}
public static void main(String[] args) throws IOException {
int dwDummy = 0;
int versionlength = Version.INSTANCE.GetFileVersionInfoSizeW(
"C:\\Test\\chromeinstall.exe", dwDummy);
byte[] bufferarray = new byte[versionlength];
Pointer lpData = new Memory(bufferarray.length);
PointerByReference lplpBuffer = new PointerByReference();
IntByReference puLen = new IntByReference();
boolean FileInfoResult = Version.INSTANCE.GetFileVersionInfoW(
"C:\\Test\\chromeinstall.exe",
0, versionlength, lpData);
System.out.println(FileInfoResult);
int verQueryVal = Version.INSTANCE.VerQueryValueW(lpData,
"\\", lplpBuffer,
puLen);
VS_FIXEDFILEINFO lplpBufStructure = new VS_FIXEDFILEINFO(
lplpBuffer.getValue());
lplpBufStructure.read();
short[] rtnData = new short[4];
rtnData[0] = (short) (lplpBufStructure.dwFileVersionMS >> 16);
rtnData[1] = (short) (lplpBufStructure.dwFileVersionMS & 0xffff);
rtnData[2] = (short) (lplpBufStructure.dwFileVersionLS >> 16);
rtnData[3] = (short) (lplpBufStructure.dwFileVersionLS & 0xffff);
for (int i = 0; i < rtnData.length; i++) {
System.out.println(rtnData[i]);
}
}
回答2:
For reference, a modified version of the code by GEverding, with JNA 4, using com.sun.jna.platform.win32
package examples;
import java.io.IOException;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.VerRsrc.VS_FIXEDFILEINFO;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
public class FileVersion {
public static void main(String[] args) throws IOException {
String filePath = "C:\\Test\\chromeinstall.exe";
IntByReference dwDummy = new IntByReference();
dwDummy.setValue(0);
int versionlength =
com.sun.jna.platform.win32.Version.INSTANCE.GetFileVersionInfoSize(
filePath, dwDummy);
byte[] bufferarray = new byte[versionlength];
Pointer lpData = new Memory(bufferarray.length);
PointerByReference lplpBuffer = new PointerByReference();
IntByReference puLen = new IntByReference();
boolean fileInfoResult =
com.sun.jna.platform.win32.Version.INSTANCE.GetFileVersionInfo(
filePath, 0, versionlength, lpData);
boolean verQueryVal =
com.sun.jna.platform.win32.Version.INSTANCE.VerQueryValue(
lpData, "\\", lplpBuffer, puLen);
VS_FIXEDFILEINFO lplpBufStructure = new VS_FIXEDFILEINFO(lplpBuffer.getValue());
lplpBufStructure.read();
int v1 = (lplpBufStructure.dwFileVersionMS).intValue() >> 16;
int v2 = (lplpBufStructure.dwFileVersionMS).intValue() & 0xffff;
int v3 = (lplpBufStructure.dwFileVersionLS).intValue() >> 16;
int v4 = (lplpBufStructure.dwFileVersionLS).intValue() & 0xffff;
System.out.println(
String.valueOf(v1) + "." +
String.valueOf(v2) + "." +
String.valueOf(v3) + "." +
String.valueOf(v4));
}
}
回答3:
If you mean the information you get in Property->Details on Windows, bear in mind that it's platform dependent! That being said SIGAR has Java bindings and a FileVersionInfo class that seems close to what you need.
回答4:
Due to portability issues I believe this kind of information is not actually available in java unless you access it using a less portable approach.
For example you could write a wrapper using JNI and C++ and use the GetFileVersionInfo API (see also this JavaWorld tip) of Windows to get that kind of information from the exe. Another approach would be to use a totally external application that outputs the version of the file and use the Runtime class to create a process and interact with that application.
Other approaches would require having access to the server and providing version checking from server side:
- files contain the version number in their name,
- save a separate file accessible to java that can provide the current version
- save the date of the download on server side and checking if the current version is newer than the date when the last one was downloaded
- check the md5 to see if the version is different, in case the server can contain only versions newer or equally as new as the client one
回答5:
I modified Antonis Zafiropoulos's answer and made a handy class you can just drop into your project. Note that the fileInfoResult and verQueryVal lines must exist even though they don't appear to do anything.
package yourpackage;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.VerRsrc.VS_FIXEDFILEINFO;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
public class EXEFileInfo {
public static int MAJOR = 0;
public static int MINOR = 1;
public static int BUILD = 2;
public static int REVISION = 3;
public static int getMajorVersionOfProgram(String path) {
return getVersionInfo(path)[MAJOR];
}
public static int getMinorVersionOfProgram(String path) {
return getVersionInfo(path)[MINOR];
}
public static int getBuildOfProgram(String path) {
return getVersionInfo(path)[BUILD];
}
public static int getRevisionOfProgram(String path) {
return getVersionInfo(path)[REVISION];
}
public static int[] getVersionInfo(String path) {
IntByReference dwDummy = new IntByReference();
dwDummy.setValue(0);
int versionlength = com.sun.jna.platform.win32.Version.INSTANCE.GetFileVersionInfoSize(path, dwDummy);
byte[] bufferarray = new byte[versionlength];
Pointer lpData = new Memory(bufferarray.length);
PointerByReference lplpBuffer = new PointerByReference();
IntByReference puLen = new IntByReference();
boolean fileInfoResult = com.sun.jna.platform.win32.Version.INSTANCE.GetFileVersionInfo(path, 0, versionlength, lpData);
boolean verQueryVal = com.sun.jna.platform.win32.Version.INSTANCE.VerQueryValue(lpData, "\\", lplpBuffer, puLen);
VS_FIXEDFILEINFO lplpBufStructure = new VS_FIXEDFILEINFO(lplpBuffer.getValue());
lplpBufStructure.read();
int v1 = (lplpBufStructure.dwFileVersionMS).intValue() >> 16;
int v2 = (lplpBufStructure.dwFileVersionMS).intValue() & 0xffff;
int v3 = (lplpBufStructure.dwFileVersionLS).intValue() >> 16;
int v4 = (lplpBufStructure.dwFileVersionLS).intValue() & 0xffff;
System.out.println("Version: " + v1 + "." + v2 + "." + v3 + "." + v4);
return new int[] { v1, v2, v3, v4 };
}
}
回答6:
There is a portable solution explained here (and this question is more or less a duplicate).
Basically, windows executable use the PE format (and linux ones ELF) and you can use the pecoff4j library to read this information in a portable way.