2011-08-02 43 views
7

有誰知道如何通過Java獲取可執行文件/文件的版本信息。這種情況是我在本地系統上有一個文件,如果服務器上的版本更新,那麼我的系統上的版本就需要從服務器上下載文件。獲取.exe的版本信息

+2

你是什麼意思的版本? –

+1

爲什麼你只是不做一個MD5校驗和? – Zaffy

+0

你的意思是元信息(在Windows中右鍵單擊和屬性)? – dacwe

回答

8

花費數小時在線和編碼後,我發現一個使用JNA獲取文件版本信息的解決方案。

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]); 
     } 

} 
+0

感謝這個有用的代碼!對於使用它的人來說只是另一個注意事項:如果在VS_FIXEDFILEINFO是內部類的類中使用此代碼,則可能會出現「Class com.sun.jna」錯誤。結構不能訪問成員getfield「如果是這樣,只需將關鍵字'public'添加到內部類VS_FIXEDFILEINFO中以修復它。 –

+1

在Java 8中(也許更低),您必須實現getFieldOrder()方法。然而,儘管如此......但Antonis Zafiropoulos的回答仍然有效。 – Mgamerz

2

由於可移植性問題,我相信這種信息實際上並不在java中可用,除非您使用不太便攜的方法訪問它。

例如,您可以使用JNI和C++編寫包裝,並使用Windows的GetFileVersionInfo API(另請參閱this JavaWorld tip)從exe獲取這類信息。另一種方法是使用完全外部的應用程序來輸出文件的版本,並使用Runtime類創建一個進程並與該應用程序進行交互。

其他方法將需要能夠訪問到服務器,並提供版本從服務器端檢查:

  • 文件的名稱中包含的版本號,
  • 訪問一個單獨的文件保存到Java,可以提供當前版本
  • 在服務器端保存下載日期並檢查當前版本是否比最後一個下載日期更新
  • 檢查md5以查看版本是否不同,以防服務器只能包含新版本或與客戶端一樣新的版本
+0

我喜歡這種方法。我在我的項目的其他部分使用JNA,而且它的JNI好很多,所以我會用JNA來做同樣的事情。謝謝 – GEverding

1

如果您的意思是您在Windows上的Property-> Details中獲取的信息,請記住它取決於平臺!這就是說SIGAR有Java綁定和一個類似於你所需要的類。

5

僅供參考,修改後的版本由GEverding代碼,與JNA 4,採用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)); 
    } 
} 
1

我修改安東尼Zafiropoulos的回答,並提出了方便類你可以放入你的項目。請注意,fileInfoResult和verQueryVal行必須存在,即使它們看起來沒有任何作用。

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 }; 
    } 
} 
0

有便攜式溶液explained here(這個問題是更多或更少的重複)。

基本上,Windows可執行文件使用PE格式(和linux的ELF),您可以使用the pecoff4j library以便攜方式讀取此信息。