閱前聲明:
http://blog.csdn.net/heimaoxiaozi/archive/2007/01/19/1487884.aspx
Jar檔案的基本操作
1.建立相關
/>jar cf jar-file input-file(s)
/*
說明,windows下和UNIX下對目錄結構的分隔字元習慣不同,前者為/,後者為/ ,本文僅僅為了說明問題,並不嚴格加以說明。——注意,無論任何平
台,在manifest檔案中均採用/
*/
/*
該形式的命令在目前的目錄下建立一個jar-file
c開關指明“建立”一個jar檔案
f開關指明輸出到檔案,而不是stdout(標準輸出)
jar-file如果不指明尾碼,則預設為*.jar
空格用於分隔多個輸入檔案,可以使用萬用字元“*”
有必要時指明目錄
開關出現的順序不重要,但是如果有m開關則另當別論。
該命令預設建立一個manifest檔案
*/
/*
對於java版本1,jar檔案僅支援ASCII作檔案名稱,java版本2則支援UTF-8編碼的檔案名稱。
*/
/*
關於建立,可用的其他開關:
v 當jar檔案建立時,在stderr(java版本1)或stdout(java版本2)產生冗餘(verbose)輸出。報告添加到jar的檔案名稱錄。
0 (zero)指明不要壓縮。
M 指明不要產生預設的manifest檔案。
m 添加手工已編製好的manifest檔案:
/>jar cmf existing-manifest jar-file input-file(s)
-C 在操作過程中轉變目錄(僅對java版本2)。
*/
/*
一個例子。
假設,如下目錄結構(windows下):
TicTacToe/TicTacToe.class (檔案)
TicTacToe/audio (子目錄,該層下全是au檔案)
TicTacToe/images (子目錄,該層下全是gif檔案)
如果要將該東東壓入jar檔案TicTacToe.jar,應在TicTacToe目錄中(!)執行下面命令:
TicTacToe>jar cvf TicTacToe.jar TicTacToe.class audio images
jar程式會自動將audio和images目錄及其子目錄一咕腦(recursively)全壓入TicTacToe.jar檔案,該檔案將出現於 TicTacToe/TicTacToe.jar
因為使用了verbose output開關,可以看到類似如下的輸出:
adding: TicTacToe.class (in=3825) (out=2222) (deflated 41%)
adding: audio/ (in=0) (out=0) (stored 0%)
adding: audio/beep.au (in=4032) (out=3572) (deflated 11%)
adding: audio/ding.au (in=2566) (out=2055) (deflated 19%)
adding: audio/return.au (in=6558) (out=4401) (deflated 32%)
adding: audio/yahoo1.au (in=7834) (out=6985) (deflated 10%)
adding: audio/yahoo2.au (in=7463) (out=4607) (deflated 38%)
adding: images/ (in=0) (out=0) (stored 0%)
adding: images/cross.gif (in=157) (out=160) (deflated -1%)
adding: images/not.gif (in=158) (out=161) (deflated -1%)
如果:
TicTacToe>jar cvf0 TicTacToe.jar TicTacToe.class audio images
則表示只備份不壓縮。
如果該目錄內全是需要jar掉的檔案及其相應目錄結構:
TicTacToe>jar cvf TicTacToe.jar *
是比較簡潔的寫法。
如果不特別使用開關m或M,預設的manifest檔案將產生於
META-INF/MANIFEST.MF
繼承了GZIP的特點,-C開關用於跳到某目錄,以改變所存入jar檔案的目錄結構。多半用於將原來位於不同目錄結構的檔案作jar時彙總在一起。例如:
TicTacToe>jar cf ImageAudio.jar -C images . -C audio .
產生的jar檔案內容和結構:
META-INF/MANIFEST.MF
cross.gif
not.gif
beep.au
ding.au
return.au
yahoo1.au
yahoo2.au
(現在假設我們images子目錄下還有子目錄,像這樣:
TicTacToe/images/jpg
jpg子目錄下還有一些*.jpg檔案那以上命令的結果應該是:
META-INF/MANIFEST.MF
jpg/AMAKUSA.jpg
jpg/UKYO.jpg
cross.gif
not.gif
beep.au
ding.au
return.au
yahoo1.au
yahoo2.au
說明了-C的真正含義。
)
*/
2.關於查看jar內容
/>jar tf jar-file
/*
t 開關指明jar檔案的內容表(table of contents)。
f 開關指明該jar檔案由命令列指出,如果不用該開關,jar則在stdin中期待一個檔案名稱。
t和f出現的順序無關,但是之間不能有空格。
該命令向stdout輸出相應jar檔案的內容表。
v 開關可以用於查看關於檔案大小、最近更改日期等等詳細內容。
*/
/*
例子。
TicTacToe>jar tf TicTacToe.jar
將在標準輸出中看到:
META-INF/MANIFEST.MF
TicTacToe.class
audio/
audio/beep.au
audio/ding.au
audio/return.au
audio/yahoo1.au
audio/yahoo2.au
images/
images/cross.gif
images/not.gif
注意,無論在任何作業系統下(windows、Linux或Unix)所有檔案結構均以正斜杠/(forward slash)分隔。而在jar檔案中的路徑顯示都是相對
(relative)的。
又例。
TicTacToe>jar tvf TicTacToe.jar
顯示如下:
256 Mon Apr 20 10:50:28 PDT 1998 META-INF/MANIFEST.MF
3885 Mon Apr 20 10:49:50 PDT 1998 TicTacToe.class
0 Wed Apr 15 16:39:32 PDT 1998 audio/
4032 Wed Apr 15 16:39:32 PDT 1998 audio/beep.au
2566 Wed Apr 15 16:39:32 PDT 1998 audio/ding.au
6558 Wed Apr 15 16:39:32 PDT 1998 audio/return.au
7834 Wed Apr 15 16:39:32 PDT 1998 audio/yahoo1.au
7463 Wed Apr 15 16:39:32 PDT 1998 audio/yahoo2.au
0 Wed Apr 15 16:39:44 PDT 1998 images/
157 Wed Apr 15 16:39:44 PDT 1998 images/cross.gif
158 Wed Apr 15 16:39:44 PDT 1998 images/not.gif
*/
3. 釋放檔案
/>jar xf jar-file [archived-file(s)]
/*
x 開關是“釋放檔案”的標誌
f 開關指明是由命令列提供待釋放jar檔案的檔案名稱,而不是stdin
jar-file 可以是一個帶有路徑的檔案
[archived-file(s)] 指出期待釋放的內容,如果略去這個參數,則將jar-file中的內容完全釋放。
釋放之後,原jar檔案保持不變。
注意,當釋放檔案時,jar會覆蓋目標目錄下同名的檔案(但之下不同名的目錄和檔案不會被洗掉(——覆蓋的原則!))。
*/
/*
例子。
TicTacToe>jar xf TicTacToe.jar TicTacToe.class images/cross.gif
該命令做兩件事情:
在目前的目錄下產生一個TicTacToe新的拷貝。
在目前的目錄下產生子目錄images,並在其下產生一個cross.gif新的拷貝。如果該目錄已經存在,則只作後一個動作。
可以用命令:
TicTacToe>jar xf TicTacToe.jar
釋放整個TicTacToe.jar檔案。
*/
4.jar歸檔和相應描述檔案(manifest file)
jar歸檔實現多種功能,例如electronic signing, version control, package sealing, extensions。其中的 manifest檔案發生了不可替
代的作用。
manifest像一個歸檔內容清單。(The manifest is a special file that can contain information about the files packaged in a JAR file.
)
manifest檔案的預設和定製方法前面已經描述,下面看內容。
預設的MANIFEST.MF(java版本2製造):
————————————
Manifest-Version: 1.0
————————————
可見,manifest檔案的表項形式為"header: value",由預設產生的manifest檔案表項(entry)只包括描述manifest自身的一項(版本)。
java版本1和java版本2都對應相同的manifest標準(manifest版本一)。但是,兩個java版本的jar產生的預設manifest檔案卻是不同的。如果是java版
本1,則產生MANIFEST.MF如下形式:
————————————
Manifest-Version: 1.0
Name: java/math/BigDecimal.class
SHA1-Digest: TD1GZt8G11dXY2p4olSZPc5Rj64=
MD5-Digest: z6z8xPj2AW/Q9AkRSPF0cg==
Name: java/math/BigInteger.class
SHA1-Digest: oBmrvIkBnSxdNZzPh5iLyF0S+bE=
MD5-Digest: wFymhDKjNreNZ4AzDWWg1Q==
————————————
可見,java版本1的MANIFEST.MF對jar包中每一個檔案都有所描述,表項包括檔案的路徑名(pathname)和摘要值(digest value,指由檔案內容產生
的某種雜湊密文)。——注意Name和Digest之間沒有空行。
這裡的摘要值一般用於對jar檔案簽名(sign),但由於它不是總是很有必要,於是在java版本2中將其省掉了。(也是為了更好地將功能結構化。)
一言以蔽之,manifest記錄什麼樣的檔案資訊完全取決於jar包的用途。(Exactly what file information is recorded in the manifest will
depend on what use you intend for the JAR file.)你可以根據jar檔案打算扮演的何種角色,來修改manifest檔案。
如果僅僅將jar用作一種簡單的壓縮方式(像一種zip),則不必關心manifest檔案。
manifest用作特定用途(以下僅對java版本2):
1)java應用程式(application)以jar檔案形式捆綁(bundle)
表項 Main-Class: classname 指明程式的入口(entry point)——即含有方法public static void main(String[] args){}的類。
2)下載擴充(Download Extensions)
下載擴充是指被其他jar檔案的manifest檔案所引用的jar檔案(http://java.sun.com/docs/books/tutorial/ext/index.html)。
舉典型一例,某個applet會被捆綁在一個jar檔案內,該jar的manifest引用(指向)了一個或多個其他jar檔案(這些檔案serve as an extension(or
extensions) for the purpose of that applet)。當然,擴充之間可以相互引用。
下載擴充由引用者的相應manifest檔案以Class-Path為頭部(header field)的表項指明,例如:
Class-Path: servlet.jar infobus.jar acme/beans.jar
注意,The URLs in the Class-Path header are given relative to the URL of the JAR file of the applet or application.
3)包密封(Package Sealing)
這是指定義在同一個package內的所有的class都打包在同一個jar檔案內。這樣,可以保證版本一致性(version consistency)或者作為一種安全措施
(security measure)——避免預設的package可視性(目前的目錄.加入classpath之後)。
Seal一個包,格式如此:
————————————————
Name: myCompany/myPackage/
Sealed: true
————————————————
Name頭(head)的值(value)指明該包對應的相對路徑名(代碼中"package myCompany.myPackage;")。(注意,它以/結尾以區別於檔案名稱)。
4)包版本控制(Package Versioning)
參見 http://java.sun.com/products/jdk/1.2/docs/guide/versioning/spec/VersioningSpecification.html#PackageVersioning
一個例子。
————————————————
Name: java/util/
Specification-Title: "Java Utility Classes"
Specification-Version: "1.2"
Specification-Vendor: "Sun Microsystems, Inc.".
Implementation-Title: "java.util"
Implementation-Version: "build57"
Implementation-Vendor: "Sun Microsystems, Inc."
————————————————
關於manifest格式的specification:
http://java.sun.com/products/jdk/1.2/docs/guide/jar/manifest.html
下面有關jar工具的m開關的說明。
如果要使用m開關,則先要準備一個用作manifest的文字檔。m開關的意思是合并(merge),作用是將該檔案的內容(!)附加在預設的(或者已有
的)manifest之上(注意不是替換!)。
/>jar cmf manifest-addition jar-file input-file(s)
/>jar cfm jar-file manifest-addition input-file(s)
產生同樣的結果,注意開關和參數的對應關係!
一個例子,用以說明jar、manifest和package的seal……
假設jar檔案準備包含下列package(注意package沒有進行jar時和目錄是對應的):
myCompany/firstPackage/
myCompany/secondPackage/
myCompany/thirdPackage/
myCompany/fourthPackage/
如果要seal了firstPackage和thirdPackage,應該寫一個這樣的manifest:
sealInfo
————————————————
Name: myCompany/firstPackage/
Sealed: true
Name: myCompany/thirdPackage/
Sealed: true
————————————————
注意,該文字檔需要以一對斷行符號換行結束,否則難通過parse程式。
設目前的目錄為myCompany的父目錄。則,
>jar cmf sealInfo myJar.jar myCompany
在myJar.jar中產生了如下的manifest文檔:
————————————————
Manifest-Version: 1.0
Name: myCompany/firstPackage/
Sealed: true
Name: myCompany/thirdPackage/
Sealed: true
————————————————
其中,第一行來自預設manifest,其他來自手工添加。
5.更新jar檔案
java版本2的u開關用於更新已存在的jar檔案(通過修改他的manifest或者增添新的檔案)。
/>jar uf jar-file input-file(s)
u開關指明更新一個已存在的jar檔案。
input-file(s)是將要add進jar-file裡的檔案清單,以空格分隔。
用這個命令,jar-file裡同名同路徑的檔案將被覆蓋。
正如前面建立jar檔案所述,可以用-C開關轉換路徑。
/>jar umf manifest1 jar-file
該命令歸併manifest1到jar-file的manifest檔案中。
一個例子。
TicTacToe.jar有如下內容:
META-INF/MANIFEST.MF
TicTacToe.class
audio/
audio/beep.au
audio/ding.au
audio/return.au
audio/yahoo1.au
audio/yahoo2.au
images/
images/cross.gif
images/not.gif
設將要向jar歸檔中加入images/new.gif,應該在images的父目錄中執行:
TicTacToe>jar uf TicTacToe.jar images/new.gif
則修改過的jar歸檔應該有如下內容:
META-INF/MANIFEST.MF
TicTacToe.class
audio/
audio/beep.au
audio/ding.au
audio/return.au
audio/yahoo1.au
audio/yahoo2.au
images/
images/cross.gif
images/not.gif
images/new.gif
如果,
TicTacToe>jar uf TicTacToe.jar -C images new.gif
該命令會在添加new.gif檔案前先轉到目錄images,歸檔結果就不會將images路徑包括進去了。結果:
META-INF/MANIFEST.MF
TicTacToe.class
audio/
audio/beep.au
audio/ding.au
audio/return.au
audio/yahoo1.au
audio/yahoo2.au
images/
images/cross.gif
images/not.gif
new.gif
最後,假設想更改TicTacToe.jar的manifest檔案(添加一些版本和銷售商資訊),應該先準備如下文字文件:
versionInfo
————————————————
Name: TicTacToe.class
Implementation-Title: "TicTacToe demo"
Implementation-Version: "build57"
Implementation-Vendor: "Sun Microsystems, Inc."
————————————————
然後,
TicTacToe>jar umf versionInfo TicTacToe.jar
更新就搞定啦。
6.執行以jar歸檔的軟體
三種情況:
1)jar歸檔了applet,被瀏覽器瀏覽
2)jar歸檔了application,在命令列調用
3)jar包含了將被用以擴充(extension)的代碼
(前兩種情況將在下面描述,3)參見URL: http://java.sun.com/docs/books/tutorial/ext/index.html)
對於applet,html中如下例:
————————————————
<applet code=TicTacToe.class
width=120 height=120>
</applet>
————————————————
如果該class在jar歸檔內,用參數archive:
————————————————
applet code=TicTacToe.class
archive="TicTacToe.jar"
width=120 height=120>
</applet>
————————————————
如果該jar和該html不在同一目錄下,而在目前的目錄的子目錄applets下,
————————————————
<applet code=TicTacToe.class
archive="applets/TicTacToe.jar"
width=120 height=120>
</applet>
————————————————
對於application,在java版本1的平台上。
可以使用jre工具:
/>jre -cp app.jar MainClass
-cp 開關將app.jar預添加到系統classpath中。
如果是在java版本2的平台上。
/>java -jar jar-file
注意,java版本2之前的java命令不支援-jar開關。
當然,runtime environment必需知道程式的進入點(Mainclass)。前面說過,這是manifest的任務了。在manifest中:
Main-Class: classname
例如:
————————————————
Main-Class: HelloWorld
————————————————