1. 程式人生 > 其它 >使用Java命令列編譯和打包jar

使用Java命令列編譯和打包jar

背景:

​ 原先測試一個OCR識別的介面為了方便呼叫,寫了一個main方法的java類,打成了jar包,在windows環境下用bat指令碼呼叫。bat指令碼中也就是利用java -jar去掉用,然後利用main方法的args陣列引數動態傳參,最後記一下輸出和錯誤。

java -jar testocr.jar param1 param2 param3 http://127.0.0.1/cxfServerX/ 1>>work.log 2>>err.txt

​ 今天由於介面變動,這個main方法中的一個地方需要修改,也就是這個jar包需要重新打,最開始這個jar包是用myeclipse直接打的,並且在jar包裡也保留了java原始檔,總共就一個java檔案,其他都是一些依賴的jar包。因為檔案數量不多也不復雜,所以乾脆直接在cmd下用命令編譯打包。

使用JAVAC編譯:

  1. 找到上次打好的jar包testocr.jar,複製一下留作備份,然後解壓成目錄testocr

    目錄結構:

    testocr
      -com/		// 存放原始碼檔案 com/xxx/xxx.java
      -jar/		// 裡面是所有依賴的jar包檔案
      -META-INF/	// 裡面有MANIFEST.MF檔案,描述jar檔案所依賴的檔案
      .classpath	// 描述專案引用的jar包
      .project	        // 專案描述檔案
    
  2. 先修改原始碼檔案,進入到com/test/目錄下,修改TestOCR.java檔案

  3. 修改後要對原始檔進行編譯,先隨便試一下。

    # 剛開始沒有指定編碼時報錯了中文亂碼,這裡就先加上了,其中 -encoding "UTF-8" 和-encoding UTF-8 加不加引號都可以
    base$ javac -encoding UTF-8 TestOCR.java
    TestOCR.java:6: 錯誤: 程式包net.sf.json不存在
    import net.sf.json.JSONObject;
                      ^
    TestOCR.java:8: 錯誤: 程式包org.apache.http不存在
    import org.apache.http.HttpEntity;
                          ^
    TestOCR.java:9: 錯誤: 程式包org.apache.http.client.methods不存在
    import org.apache.http.client.methods.CloseableHttpResponse;
                                         ^
    TestOCR.java:10: 錯誤: 程式包org.apache.http.client.methods不存在
    import org.apache.http.client.methods.HttpPost;
                                         ^
    TestOCR.java:11: 錯誤: 程式包org.apache.http.entity不存在
    import org.apache.http.entity.StringEntity;
    ...
    
    # 這個報錯是意料之中的,因為TestOCR.java中import了很多三方jar包,需要指定一下類路徑
    
  4. 指定依賴的三方jar包類路徑後執行

    # 首先就是javac -cp 和 javac -classpath是一樣的,直接輸入javac在幫助命令中也可以看出來
    	...
      -classpath <路徑>            指定查詢使用者類檔案和註釋處理程式的位置
      -cp <路徑>                   指定查詢使用者類檔案和註釋處理程式的位置
      ...
    # 這裡我用相對路徑,TestOCR.java依賴的jar包都放在這個jar目錄下  
    base$ javac -encoding UTF-8 -cp ../../jar/ TestOCR.java
    
    TestOCR.java:6: 錯誤: 程式包net.sf.json不存在
    import net.sf.json.JSONObject;
                      ^
    TestOCR.java:8: 錯誤: 程式包org.apache.http不存在
    ...
    # 結果還是報錯 很明顯還是找不到依賴包 但是路徑確實是正確的
    # 然後我去掉最後一個/ 執行
    base$ javac -encoding UTF-8 -cp ../../jar TestOCR.java
    
    # 很遺憾還是報錯,然後我又嘗試一下使用*去匹配所有.jar字尾的檔案
    base$ javac -encoding UTF-8 -cp ../../jar/*.jar TestOCR.java 
    javac: 無效的標記: ../../jar/XmlSchema-1.4.3.jar
    用法: javac <options> <source files>
    -help 用於列出可能的選項
    
    # 這裡感覺好像是javac直接懟到 依賴的jar包上去了,所以直接報錯了,換一種寫法
    base$ javac -encoding UTF-8 -cp ../../jar/* TestOCR.java 
    javac: 無效的標記: ../../jar/XmlSchema-1.4.3.jar
    用法: javac <options> <source files>
    -help 用於列出可能的選項
    
    # 加個引號試試
    base$ javac -encoding UTF-8 -cp "../../jar/*" TestOCR.java 
    # 編譯正確,在TestOCR.java檔案的相同目錄下出現了TestOCR.class檔案
    
    # 可以使用-d指定class檔案的生成路徑,並且會按java檔案的 package包名生成檔案目錄結構
    base$ javac -encoding UTF-8 -cp "../../jar/*" -d . TestOCR.java 
    # 加上-d . 後,就在當前目錄下生成了TestOCR.java的package包名結構的檔案目錄,並將TestOCR.class放在此目錄下
    
    

    打JAR包

    1. 因為jar包剛開始是從Myeclipse中打好的,所以MANIFEST.MF都是有的,當時也是手動寫的,按照格式指定一下主類和依賴的包路徑,記得需要注意幾點:

      • 這個Class-Path後面的路徑名稱太多了話不能寫到一行,寫很多到一行會報錯行太長,直接換行寫就行,但是換行時從第二行開始要先敲兩個空格,後面再換行也要先有兩個空格

      • key: value,key之後跟冒號再跟空格,這點跟yaml很像,還有Class-Path中的多個jar包路徑之間也是用空格分隔的。

      • Class-Path寫完之後最後一定要有一個空行

      • 注意Class-Path的路徑和生成好的Jar包的路徑,這裡我寫的相對路徑,相當於打好的jar包和lib在同一目錄下,這樣才能找到依賴的jar包路徑。

        testocr
          -testocr.jar	 // 打好的jar包
          -lib/				// 裡面是所有依賴的jar包檔案
        
      Manifest-Version: 1.0
      Main-Class: com.test.TestOCR
      Class-Path: lib/commons-beanutils.jar lib/commons-collections-3.2.jar lib/commons-httpclient.jar 
        lib/commons-io-2.2.jar lib/commons-lang-2.4.jar lib/commons-logging.jar 
      Name: com/test/
      Sealed: true
      
    2. 使用jar命令進行打包

      # 看一下引數
      base$ jar
      用法: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...
      選項:
          -c  建立新檔案
          -t  列出檔案目錄
          -x  從檔案中提取指定的 (或所有) 檔案
          -u  更新現有檔案
          -v  在標準輸出中生成詳細輸出
          -f  指定檔案檔名
          -m  包含指定清單檔案中的清單資訊
          -n  建立新檔案後執行 Pack200 規範化
          -e  為捆綁到可執行 jar 檔案的獨立應用程式
              指定應用程式入口點
          -0  僅儲存; 不使用任何 ZIP 壓縮
          -P  保留檔名中的前導 '/' (絕對路徑) 和 ".." (父目錄) 元件
          -M  不建立條目的清單檔案
          -i  為指定的 jar 檔案生成索引資訊
          -C  更改為指定的目錄幷包含以下檔案
      如果任何檔案為目錄, 則對其進行遞迴處理。
      清單檔名, 檔案檔名和入口點名稱的指定順序
      與 'm', 'f' 和 'e' 標記的指定順序相同。
      
      示例 1: 將兩個類檔案歸檔到一個名為 classes.jar 的檔案中: 
             jar cvf classes.jar Foo.class Bar.class 
      示例 2: 使用現有的清單檔案 'mymanifest' 並
                 將 foo/ 目錄中的所有檔案歸檔到 'classes.jar' 中: 
             jar cvfm classes.jar mymanifest -C foo/ .
      
      # 使用描述清單將當前目錄下所有檔案打包成 testocr.jar
      base$ jar -cvfm testocr.jar META-INF/MANIFEST.MF *
      已新增清單
      正在忽略條目META-INF/
      正在忽略條目META-INF/MANIFEST.MF
      正在新增: META-INF/REFACTORINGS.XML(輸入 = 64) (輸出 = 52)(壓縮了 18%)
      正在新增: com/(輸入 = 0) (輸出 = 0)(儲存了 0%)
      正在新增: com/test/(輸入 = 0) (輸出 = 0)(儲存了 0%)
      正在新增: com/test/TestOCR.java(輸入 = 4309) (輸出 = 1816)(壓縮了 57%)
      正在新增: com/test/TestOCR.class(輸入 = 3420) (輸出 = 1841)(壓縮了 46%)
      正在新增: jar/(輸入 = 0) (輸出 = 0)(儲存了 0%)
      ...
      
      # 使用 jar -tf testocr.jar 檢視一下jar包內的檔案
      base$ jar -tf testocr.jar
      META-INF/
      META-INF/MANIFEST.MF
      META-INF/REFACTORINGS.XML
      com/
      com/test/
      com/test/TestOCR.java
      com/test/TestOCR.class
      jar/
      jar/spring-context-2.0.8.jar
      jar/json.jar
      ...
      
      # 檢查後沒有問題 可以使用了,最後執行就java -jar testocr.jar即可,已經用bat指令碼寫好了互動,完成
      

      總結:

      ​ 使用這些命令處理一些簡單的類還是很方便的,對於複雜的還是使用開發工具去搞比較合適。