coolfiry

认认真真做人,兢兢业业做事!
posts - 39, comments - 17, trackbacks - 0, articles - 0

 和 'f'标志指定的相同顺序。

示例1:将两个class文件存档到一个名为 'classes.jar' 的存档文件中:
 & nbsp;     jar cvf& nbsp;classes.jar Foo.class Bar.class
示例2:用一个存在的清单(manifest)文件 'mymanifest' 将 foo/& nbsp;目录下的所有
            文件存档到一个名为  'classes.jar' 的存档文件中:
        jar cvfm  classes.jar mymanifest -C foo/ .

来个小例子试试看:
我们只有一个HelloWorld,如下:
public& nbsp; class  HelloWorld{
 public& nbsp;static void main(String[] args){
 System.out.println(“Hi, Hello World!”);
}
}
我将这个java文件存到C盘跟目录下,ok,接下来,
在先前打开的命令提示符下(跳转到C盘提示符下),我们输入javac HelloWorld.java,然后继续输入:jar & nbsp;cvf  hello.jar  HelloWorld.class,回车后去你的C盘看看,多了什么,没错 hello.jar 。
基本的步骤我们现在都知道了,你可以自己去尝试一下随着jar后面的参数的不同,结果有什么变化。
紧接着我们看看如何运行我们的jar包。
在进入正题之前,你要先打开我们刚刚做好的jar包看看,多了什么呢,META-INF目录?再看看里面是什么,还有一个MANIFEST.MF文件是不是?用文本编辑器(我这里是UltraEdit)打开它看看:
Manifest-Version:  1.0
Created-By: 1.4.2 (Sun Microsystems& nbsp;Inc.)
就是这样。这里我们对它进行修改,加一句:Main-Class:  HelloWorld (在第三行)。这个就是我们之前写的那个类,也就是我们的入口类。也即,
Manifest -Version: 1.0
Created-By: 1.4.2 (Sun& nbsp;Microsystems Inc.)
Main-Class: HelloWorld< BR>接下来,我们在命令提示符里执行:
jar umf  MANIFEST.MF app.jar
这样我们使用了我们自己的MANIFEST.MF文件对原来默认的进行了更新。你不妨可以再进去看看是不是添上了Main-Class: HelloWorld这一句。
Ok,这个最后的一步了,来验证我们做的一切,在命令提示符中输入:
java -jar hello.jar (执行)
出现了什么,――Hi, Hello World!
我们再来看看 jar文件在tomcat中发布,注意:在tomcat中我们就不能再用jar这种格式,而改war格式,它是专门用于web应用的,其实整个过程下来基本上和jar是类似的:
先准备我们要打包的资源。
找到存放tomcat的webapps目录,进到其中,新建一个文件夹,这里命名为hello,再进去新建WEB-INF文件夹,再进去新建classes文件夹,此时我们也将我们唯一的servlet, HelloWorld.java放到这里,在与classes目录同级下建立一文件web.xml。Ok,目前我们初步建立了一个简单的web应用。
这是HelloWorld.java:
import java.io.*;< BR>import javax.servlet.*;
import javax.servlet.http.*;
public class HelloWorld extends& nbsp;HttpServlet {
 public void  doGet(HttpServletRequest req, HttpServletResponse  res)
              & nbsp;               & nbsp; throws ServletException, IOException& nbsp;{
  res.setContentType("text/html");
  PrintWriter out = res.getWriter ();
  out.println("<HTML>");< BR>  out.println("<HEAD><TITLE& gt;Hello, World!</TITLE></HEAD>");< BR>  out.println("<BODY>");
& nbsp; out.println("Hello, World!");
   out.println("</BODY></HTML>");
 }
}//end here!
对它编译。下面是web.xml:< BR><?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC
  '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN'
  'http://java.sun.com/j2ee/dtds/web-app_2_3.dtd&< /FONT>#39;>
<web-app>
  <servlet>
     <servlet-name>hello</servlet-name& gt;
    <servlet-class& gt;HelloWorld</servlet-class>
   </servlet>
  <servlet-mapping& gt;
 <servlet-name>hello</servlet- name>
 <url-pattern>/HelloWorld& lt;/url-pattern>
  </servlet-mapping& gt;
</web-app>
开始压缩,形成war档:
在命令提示符下进到先前创制的hello目录下,执行 jar  cvf   hello.war  * ,我们便得到hello.war。将它拷贝至 webapps目录下,ok,来看最后一步,打开tomcat的目录conf中的server.xml,加入:
   <Context path="/hello" docBase="hello.war"& nbsp;debug="0"
    reloadable ="true"/>
大功告成!运行它,启动tomcat,后在浏览器中输入http://localhost:8080/hello/HelloWorld,有了吗?
最后,如果你想用ant来完成以上的打包活动,下面就告诉你:
对于jar来说。在build.xml 中,
 <target name="jar">< BR>  <jar destfile="${app_home}/hello.jar"& gt;
   <fileset dir=" ${dest}" includes="**"/>
  & nbsp;   <!--fileset dir="${dest} " includes="**/action.properties"/-->
     </jar>
 & lt;/target>

对于war,
<war& nbsp;warfile="hello.war" webxml="./WEB-INF/web.xml">
    <fileset dir="html"/& gt;
    <lib  dir="lib/">
    & nbsp;   <exclude name="oracle*.jar"/& gt;
    </lib>
    <classes  dir="build/servlets">
   & nbsp;     <include& nbsp;name="**/*.class"/>
  </classes& gt;
</war> 
好了,就这么多,希望对你有点帮助。:)
我上传了上面打过的两个包,hello.jar和hello.war。『 点击下载』
『 点击下载』
第一rar文件对应的是hello.jar,下载后将其名改为 hello.jar
第二rar文件对应hello.war,下载后改为hello.war。
这是由于上传不了 jar格式和war格式的文件,你只好照我上面说的去做了 :)

补充:
############
jar基本操作:
############
1.& nbsp;创建jar文件
  jar cf jar- file input-file(s)
c---want to Create& nbsp;a JAR file.
f---want the  output to go to a file  rather than to stdout.
eg: 1) jar cf myjar.jar query_maintain_insert.htm< BR>    2)jar cvf  myjar.jar query_maintain_insert.htm
       v---Produces verbose(详细的) output.
    3)jar& nbsp;cvf myjar.jar query_maintain_insert.htm mydirectory< BR>    4)jar cv0f  myjar.jar query_maintain_insert.htm mydirectory
      0---don't& nbsp;want the JAR file to be& nbsp;compressed.
    5)jar& nbsp;cmf MANIFEST.MF myjar.jar yahh.txt
      m---Used& nbsp;to include manifest information  from an existing manifest file.
    6)jar cMf MANIFEST.MF& nbsp;myjar.jar yahh.txt
   & nbsp;  M---the default manifest  file should not be produced.
    7)jar cvf myjar.jar& nbsp;*
       *---create all contents in current& nbsp;directory.
2. 察看jar文件
 & nbsp;jar tf jar-file
t---want to& nbsp;view the Table of contents  of the JAR file.
eg: 1)jar& nbsp;vft yahh.jar
       v---Produces verbose(详细的)  output.
3. 提取jar文件
   jar xf jar-file [archived-file(s)]
x- --want to extract files from  the JAR archive.
eg: 1)jar xf& nbsp;yahh.jar yahh.txt(仅提取文件yahh.txt)
 & nbsp;  2)jar xf yahh.jar alex/yahhalex.txt (仅提取目录alex下的文件yahhalex.txt)
   & nbsp;3)jar xf yahh.jar(提取该jar包中的所有文件或目录)
4. 修改Manifest文件
  jar  cmf manifest-addition jar-file input-file(s)< BR>m---Used to include manifest information& nbsp;from an existing manifest file.< BR>5. 更新jar文件
  jar  uf jar-file input-file(s)
u---want to update a

posted @ 2006-10-12 18:40 Coolfiry 阅读(341) | 评论 (0)编辑 收藏

发布Java应用程序时你会感到困难?好在Java提供了一系列打包和发布工具,可以显著的简化发布过程
  
  该文章提供了打包Java code的几种方法,我们将会探讨Java manifest 文件,给出用于管理JAR文件所依赖文件、估计跨平台发布所需的CLasspath的合适方法.我也会解释如何使用manifest包版本特性来确认包的兼容性...
  
  什么是JAR文件?
  
  在开发过程中,我们可以直接使用Java class文件来运行程序,但这并不是一个好方式,好在Java 提供了 JAR(Java Archive)文件来提供发布和运行。
  
  jar 文件实际上是class 文件的ZIP压缩存档,这种格式被广泛使用,因此易与使用,有很多中工具可以操作这种格式的文件。也正是因为这个原因,jar文件本身并不能表达所包含应用程序的标签信息。
  
  Manifest 因此得以出现
  
   为了要提供存档的标签信息,jar 文件指定了一个特定目录来存放标签信息:META-INF 目录,其中我们来关注该目录中的MANIFEST.MF文件,他就是JAR的manifest文件,他包含了JAR文件的内容描述,并在运行时向JVM提 供应用程序的信息,大多数JAR文件含有一个默认生成的manifest 文件,执行JAR命令或使用zip工具,都可以产生它
  
  如果是由jar命令产生的 manifest 文件,形如:
  Manifest-Version: 1.0
  Created-By:1.4.0-beta
  (Sun Microsystems Inc.)
  
   这些信息没甚么用,仅仅告诉我们使用的是1.0的manifest文件,第一行定义manifest的格式,第二行说明使用 SUN 的JDK1.4的jar工具生成该文件,如果manifest文件是由其他 (如ant) 创建的,那将会出现 “Created-By: Ant 1.2” 之类的内容,如果你是自己创建manifest文件,你可以加入自己的一些相关信息.
  
  基础格式
  
  manifest 文件的格式 是很简单的,每一行都是 名-值 对应的:属性名开头,接着是 ":" ,然后是属性值,每行最多72个字符,如果需要增加,你可以在下一行续行,续行以空格开头,以空格开头的行都会被视为前一行的续行。
  
  所有在开头的属性都是全局的,你也可以定义特定class 或package的属性,稍后将介绍这种
  
  把manifest文件插入JAR文件
  
  使用 m 选项,把指定文件名的manifest文件 传入,例如
  jar cvfm myapplication.jar myapplication.mf -C classdir
  
  如果你使用ant来创建时,在ant 的build.xml 加入如下条目
  <target name="jar">
  <jar jarfile ="myapplication.jar"
  manifest="myapplication.mf">
  <fileset dir="classdir"
  includes="**/*.class"/>
  </jar>
  </target>
  
  运行Java程序
  
  现在我们来体验一下manifest文件的作用,如果现在我们有一个Java 应用程序打包在myapplication.jar中, main class为 com.example.myapp.MyAppMain ,那么我们可以用以下的命令来运行
  java -classpath myapplication.jar com.example.myapp.MyAppMain
  
  这显然太麻烦了,现在我们来创建自己的manifest文件,如下:
  Manifest-Version: 1.0
  Created-By: JDJ example
  Main-Class: com.example.myapp.MyAppMain
  
  这样我们就可以使用如下的命令来运行程序了:(明显简单多了,也不会造成无谓的拼写错误)
  java -jar myapplication.jar
  
  管理JAR的依赖资源
  
   很少Java应用会仅仅只有一个jar文件,一般还需要 其他类库。比如我的应用程序用到了Sun 的 Javamail classes ,在classpath中我需要包含activation.jar 和 mail.jar,这样在运行程序时,相比上面的例子,我们要增加一些:
  java -classpath mail.jar:activation.jar -jar myapplication.jar
  
  在不同的操作系统中,jar包间的分隔符也不一样,在UNIX用“:”,在window中使用 “;”,这样也不方便
  
  同样,我们改写我们的manifest文件,如下
  Manifest-Version: 1.0
  Created-By: JDJ example
  Main-Class: com.example.myapp.MyAppMain
  Class-Path: mail.jar activation.jar
  
  (加入了Class-Path: mail.jar activation.jar,用空格分隔两个jar包)
  
  这样我们仍然可以使用和上例中相同的命令来执行该程序:
  java -jar myapplication.jar
  
   Class-Path属性中包含了用空格分隔的jar文件,在这些jar文件名中要对特定的字符使用逃逸符,比如空格,要表示成"%20",在路径的表 示中,都采用“/”来分隔目录,无论是在什么操作系统中,(即使在window中),而且这里用的是相对路径(相对于本身的JAR文件):
  Manifest-Version: 1.0
  Created-By: JDJ example
  Main-Class: com.example.myapp.MyAppMain
  Class-Path: ext/mail.jar ext/activation.jar
  Multiple Main Classes(多主类)
  
   还有一种Multiple Main Classes情况,如果你的应用程序可能有命令行版本 和GUI版本,或者一些不同的应用却共享很多相同的代码,这时你可能有多个Main Class,我们建议你采取这样的策略:把共享的类打成lib包,然后把不同的应用打成不同的包,分别标志主类:如下
  Manifest for myapplicationlib.jar:
  Manifest-Version: 1.0
  Created-By: JDJ example
  Class-Path: mail.jar activation.jar
  Manifest for myappconsole.jar:
  Manifest-Version: 1.0
  Created-By: JDJ example
  Class-Path: myapplicationlib.jar
  Main-Class: com.example.myapp.MyAppMain
  Manifest for myappadmin.jar:
  Manifest-Version: 1.0
  Created-By: JDJ example
  Class-Path: myapplicationlib.jar
  Main-Class: com.example.myapp.MyAdminTool
  在myappconsole.jar 和 myappadmin.jar的manifest文件中分别注明各自的 Main Class
  Package Versioning
  
  完成发布后,如果使用者想了解 ,哪些代码是谁的?目前是什么版本?使用什么版本的类库?解决的方法很多 ,manifest提供了一个较好的方法,你可以在manifest文件中描述每一个包的信息。
  
   Java 秉承了实现说明与描述分离的原则,package 的描述 定义了package 是什么,实现说明 定义了谁提供了描述的实现,描述和实现包含 名、版本号和提供者。要得到这些信息,可以查看JVM的系统属性(使用 java.lang.System.getProperty() )
  
  在manifest文件中,我可以为每个package定义描述和实现版本,声明名字,并加入描述属性和实现属性,这些属性是
  
  Specification-Title
  Specification-Version
  Specification-Vendor
  Implementation-Title
  Implementation-Version
  Implementation-Vendor
  
  当要提供一个类库或编程接口时,描述信息显得是很重要,见以下范例:
  
  Manifest-Version: 1.0
  Created-By: JDJ example
  Class-Path: mail.jar activation.jar
  Name: com/example/myapp/
  Specification-Title: MyApp
  Specification-Version: 2.4
  Specification-Vendor: example.com
  Implementation-Title: com.example.myapp
  Implementation-Version: 2002-03-05-A
  Implementation-Vendor: example.com
  
  Package Version 查询
  
  在manifest文件中加入package描述后,就可以使用Java提供的java.lang.Package class进行Package 的信息查询,这里列举3个最基本的获取package object的方法
  
  1.Package.getPackages():返回系统中所有定义的package列表
  
  2.Package.getPackage(String packagename):按名返回package
  
  3.Class.getPackage():返回给定class所在的package
  
  使用者这方法就可以动态的获取package信息.
  
  需要注意的是如果给定的package中没有class被加载,则也无法获得package 对象
  
  Manifest 技巧
  
  总是以Manifest-Version属性开头
  
  每行最长72个字符,如果超过的化,采用续行
  
  确认每行都以回车结束,否则改行将会被忽略
  
  如果Class-Path 中的存在路径,使用"/"分隔目录,与平台无关
  
  使用空行分隔主属性和package属性
  
  使用"/"而不是"."来分隔package 和class ,比如 com/example/myapp/
  
  class 要以.class结尾,package 要以 / 结尾

posted @ 2006-10-12 18:38 Coolfiry 阅读(287) | 评论 (0)编辑 收藏

下面就来看看什么是 JAR 文件包吧:

1. JAR 文件包

JAR 文件就是 Java Archive File,顾名思意,它的应用是与 Java 息息相关的,是 Java 的一种文档格式。JAR 文件非常类似 ZIP 文件——准确的说,它就是 ZIP 文件,所以叫它文件包。JAR 文件与 ZIP 文件唯一的区别就是在 JAR 文件的内容中,包含了一个 META-INF/MANIFEST.MF 文件,这个文件是在生成 JAR 文件的时候自动创建的。举个例子,如果我们具有如下目录结构的一些文件:

  ==

  `-- test

    `-- Test.class

把它压缩成 ZIP 文件 test.zip,则这个 ZIP 文件的内部目录结构为:

  test.zip

  `-- test

    `-- Test.class

如果我们使用 JDK 的 jar 命令把它打成 JAR 文件包 test.jar,则这个 JAR 文件的内部目录结构为:

  test.jar

  |-- META-INF

  |  `-- MANIFEST.MF

  `-- test

    `--Test.class

2. 创建可执行的 JAR 文件包

制作一个可执行的 JAR 文件包来发布你的程序是 JAR 文件包最典型的用法。

Java 程序是由若干个 .class 文件组成的。这些 .class 文件必须根据它们所属的包不同而分级分目录存放;运行前需要把所有用到的包的根目录指定给 CLASSPATH 环境变量或者 java 命令的 -cp 参数;运行时还要到控制台下去使用 java 命令来运行,如果需要直接双击运行必须写 Windows 的批处理文件 (.bat) 或者 Linux 的 Shell 程序。因此,许多人说,Java 是一种方便开发者苦了用户的程序设计语言。

其实不然,如果开发者能够制作一个可执行的 JAR 文件包交给用户,那么用户使用起来就方便了。在 Windows 下安装 JRE (Java Runtime Environment) 的时候,安装文件会将 .jar 文件映射给 javaw.exe 打开。那么,对于一个可执行的 JAR 文件包,用户只需要双击它就可以运行程序了,和阅读 .chm 文档一样方便 (.chm 文档默认是由 hh.exe 打开的)。那么,现在的关键,就是如何来创建这个可执行的 JAR 文件包。

创建可执行的 JAR 文件包,需要使用带 cvfm 参数的 jar 命令,同样以上述 test 目录为例,命令如下:

jar cvfm test.jar manifest.mf test

这里 test.jar 和 manifest.mf 两个文件,分别是对应的参数 f 和 m,其重头戏在 manifest.mf。因为要创建可执行的 JAR 文件包,光靠指定一个 manifest.mf 文件是不够的,因为 MANIFEST 是 JAR 文件包的特征,可执行的 JAR 文件包和不可执行的 JAR 文件包都包含 MANIFEST。关键在于可执行 JAR 文件包的 MANIFEST,其内容包含了 Main-Class 一项。这在 MANIFEST 中书写格式如下:

Main-Class: 可执行主类全名(包含包名)

例如,假设上例中的 Test.class 是属于 test 包的,而且是可执行的类 (定义了 public static void main(String[]) 方法),那么这个 manifest.mf 可以编辑如下:

Main-Class: test.Test <回车>

这个 manifest.mf 可以放在任何位置,也可以是其它的文件名,只需要有 Main-Class: test.Test 一行,且该行以一个回车符结束即可。创建了 manifest.mf 文件之后,我们的目录结构变为:

  ==

  |-- test

  |  `-- Test.class

  `-- manifest.mf

这时候,需要到 test 目录的上级目录中去使用 jar 命令来创建 JAR 文件包。也就是在目录树中使用“==”表示的那个目录中,使用如下命令:

jar cvfm test.jar manifest.mf test

之后在“==”目录中创建了 test.jar,这个 test.jar 就是执行的 JAR 文件包。运行时只需要使用 java -jar test.jar 命令即可。

需要注意的是,创建的 JAR 文件包中需要包含完整的、与 Java 程序的包结构对应的目录结构,就像上例一样。而 Main-Class 指定的类,也必须是完整的、包含包路径的类名,如上例的 test.Test;而且在没有打成 JAR 文件包之前可以使用 java <类名> 来运行这个类,即在上例中 java test.Test 是可以正确运行的 (当然要在 CLASSPATH 正确的情况下)。

3. jar 命令详解

jar 是随 JDK 安装的,在 JDK 安装目录下的 bin 目录中,Windows 下文件名为 jar.exe,Linux 下文件名为 jar。它的运行需要用到 JDK 安装目录下 lib 目录中的 tools.jar 文件。不过我们除了安装 JDK 什么也不需要做,因为 SUN 已经帮我们做好了。我们甚至不需要将 tools.jar 放到 CLASSPATH 中。

使用不带任何的 jar 命令我们可以看到 jar 命令的用法如下:

jar {ctxu}[vfm0M] [jar-文件] [manifest-文件] [-C 目录] 文件名 ...

其中 {ctxu} 是 jar 命令的子命令,每次 jar 命令只能包含 ctxu 中的一个,它们分别表示:

-c 创建新的 JAR 文件包

-t 列出 JAR 文件包的内容列表

-x 展开 JAR 文件包的指定文件或者所有文件

-u 更新已存在的 JAR 文件包 (添加文件到 JAR 文件包中)

[vfm0M] 中的选项可以任选,也可以不选,它们是 jar 命令的选项参数

-v 生成详细报告并打印到标准输出

-f 指定 JAR 文件名,通常这个参数是必须的

-m 指定需要包含的 MANIFEST 清单文件

-0 只存储,不压缩,这样产生的 JAR 文件包会比不用该参数产生的体积大,但速度更快

-M 不产生所有项的清单(MANIFEST〕文件,此参数会忽略 -m 参数

[jar-文件] 即需要生成、查看、更新或者解开的 JAR 文件包,它是 -f 参数的附属参数

[manifest-文件] 即 MANIFEST 清单文件,它是 -m 参数的附属参数

[-C 目录] 表示转到指定目录下去执行这个 jar 命令的操作。它相当于先使用 cd 命令转该目录下再执行不带 -C 参数的 jar 命令,它只能在创建和更新 JAR 文件包的时候可用。  

文件名 ... 指定一个文件/目录列表,这些文件/目录就是要添加到 JAR 文件包中的文件/目录。如果指定了目录,那么 jar 命令打包的时候会自动把该目录中的所有文件和子目录打入包中。

下面举一些例子来说明 jar 命令的用法:

1) jar cf test.jar test

该命令没有执行过程的显示,执行结果是在当前目录生成了 test.jar 文件。如果当前目录已经存在 test.jar,那么该文件将被覆盖。

2) jar cvf test.jar test

该命令与上例中的结果相同,但是由于 v 参数的作用,显示出了打包过程,如下:

标明清单(manifest)

增加:test/(读入= 0) (写出= 0)(存储了 0%)

增加:test/Test.class(读入= 7) (写出= 6)(压缩了 14%)

3) jar cvfM test.jar test

该命令与 2) 结果类似,但在生成的 test.jar 中没有包含 META-INF/MANIFEST 文件,打包过程的信息也略有差别:

增加:test/(读入= 0) (写出= 0)(存储了 0%)

增加:test/Test.class(读入= 7) (写出= 6)(压缩了 14%)

4) jar cvfm test.jar manifest.mf test

运行结果与 2) 相似,显示信息也相同,只是生成 JAR 包中的 META-INF/MANIFEST 内容不同,是包含了 manifest.mf 的内容

5) jar tf test.jar

在 test.jar 已经存在的情况下,可以查看 test.jar 中的内容,如对于 2) 和 3) 生成的 test.jar 分别应该此命令,结果如下;

对于 2)

META-INF/

META-INF/MANIFEST.MF

test/

test/Test.class

对于 3)

test/

test/Test.class

6) jar tvf test.jar

除显示 5) 中显示的内容外,还包括包内文件的详细信息,如:

0 Wed Jun 19 15:39:06 GMT 2002 META-INF/

86 Wed Jun 19 15:39:06 GMT 2002 META-INF/MANIFEST.MF

0 Wed Jun 19 15:33:04 GMT 2002 test/

7 Wed Jun 19 15:33:04 GMT 2002 test/Test.class

7) jar xf test.jar

解开 test.jar 到当前目录,不显示任何信息,对于 2) 生成的 test.jar,解开后的目录结构如下:

  ==

  |-- META-INF

  |  `-- MANIFEST

  `-- test

    `--Test.class

.net/forum/images/smiles/icon_cool.gif border=0> jar xvf test.jar

运行结果与 7) 相同,对于解压过程有详细信息显示,如:

创建:META-INF/

展开:META-INF/MANIFEST.MF

创建:test/

展开:test/Test.class

9) jar uf test.jar manifest.mf

在 test.jar 中添加了文件 manifest.mf,此使用 jar tf 来查看 test.jar 可以发现 test.jar 中比原来多了一个 manifest。这里顺便提一下,如果使用 -m 参数并指定 manifest.mf 文件,那么 manifest.mf 是作为清单文件 MANIFEST 来使用的,它的内容会被添加到 MANIFEST 中;但是,如果作为一般文件添加到 JAR 文件包中,它跟一般文件无异。

10) jar uvf test.jar manifest.mf

与 9) 结果相同,同时有详细信息显示,如:

增加:manifest.mf(读入= 17) (写出= 19)(压缩了 -11%)

4. 关于 JAR 文件包的一些技巧

1) 使用 unzip 来解压 JAR 文件

在介绍 JAR 文件的时候就已经说过了,JAR 文件实际上就是 ZIP 文件,所以可以使用常见的一些解压 ZIP 文件的工具来解压 JAR 文件,如 Windows 下的 WinZip、WinRAR 等和 Linux 下的 unzip 等。使用 WinZip 和 WinRAR 等来解压是因为它们解压比较直观,方便。而使用 unzip,则是因为它解压时可以使用 -d 参数指定目标目录。

在解压一个 JAR 文件的时候是不能使用 jar 的 -C 参数来指定解压的目标的,因为 -C 参数只在创建或者更新包的时候可用。那么需要将文件解压到某个指定目录下的时候就需要先将这具 JAR 文件拷贝到目标目录下,再进行解压,比较麻烦。如果使用 unzip,就不需要这么麻烦了,只需要指定一个 -d 参数即可。如:

unzip test.jar -d dest/

2) 使用 WinZip 或者 WinRAR 等工具创建 JAR 文件

上面提到 JAR 文件就是包含了 META-INF/MANIFEST 的 ZIP 文件,所以,只需要使用 WinZip、WinRAR 等工具创建所需要 ZIP 压缩包,再往这个 ZIP 压缩包中添加一个包含 MANIFEST 文件的 META-INF 目录即可。对于使用 jar 命令的 -m 参数指定清单文件的情况,只需要将这个 MANIFEST 按需要修改即可。

3) 使用 jar 命令创建 ZIP 文件

有些 Linux 下提供了 unzip 命令,但没有 zip 命令,所以需要可以对 ZIP 文件进行解压,即不能创建 ZIP 文件。如要创建一个 ZIP 文件,使用带 -M 参数的 jar 命令即可,因为 -M 参数表示制作 JAR 包的时候不添加 MANIFEST 清单,那么只需要在指定目标 JAR 文件的地方将 .jar 扩展名改为 .zip 扩展名,创建的就是一个不折不扣的 ZIP 文件了,如将上一节的第 3) 个例子略作改动:

jar cvfM test.zip test

posted @ 2006-10-12 15:54 Coolfiry 阅读(350) | 评论 (0)编辑 收藏

     摘要: 周 登朋 (zhoudengpeng@yahoo.com.cn), 软件工程师, 上海交通大学 2006 年 9 月 06 日  在本篇文章中,你会学习到如何利用 Lucene 实现高级搜索功能以及如何利用 Lucene 来创建 Web 搜索应用程序。通过这些学习,你就可以利用 Lucene 来创建自己的搜索应用程序。 ...  阅读全文

posted @ 2006-10-03 20:11 Coolfiry 阅读(359) | 评论 (1)编辑 收藏

一、闲聊

  今天要谈的话题是COM,稍微深入一点,不知道大家用过C++Test或者Visual Assistant之类的软件没有,它们都有个非常引人注目的功能,那就是把它们自身嵌入到VC开发环境中去。这个功能让我痴迷不已,原因只有一个:我想做一个可以嵌入VC开发环境的VC工程解析器,这样用户在VC开发环境中就可以直接对当前或所有工程进行各种分析,统计。那么实现它简单吗?简单,Next和Copy即可轻松完成;仅仅这些吗?不是,它的背后还有博大精深的COM做支撑。不管困难与否,还是让我们先试为快。

  二、效果图

 

  三、实现步骤:

  <3.1>新建一个<DevStudio Add-in Wizard>类型工程,输入工程名称"CodeAnalyser".

  <3.2>进入第二个画面,系统要求用户输入插件的名称和描述信息。并且要求用户选择是否需要生成工具栏以及是否自动添加VC事件响应代码。


  <3.3>点击"Finish"结束向导,进入代码编辑窗口。

  在这里我们要说的一点是:该工程引用了ICommands接口,并从该接口上派生出 CCommands类。该类完成了所有用户自定义函数接口,VC应用程序消息响应和VC调试动作的消息响应工作。当我们真正为CCommands类添加成员函数之前我们必须先为ICommands接口添加相应的函数接口声明。在本工程中我总共为ICommands接口添加了两个函数接口,它们名字分别为:GetCurDirCommandMethod和QuitCommandMethod声明如下:(在CodeAnalyer.odl文件中)

interface ICommands : IDispatch
{
 // methods
 [id(1)] //在Vtable中的函数索引号
 HRESULT GetCurDirCommandMethod(); //得到VC当前工作目录

 [id(2)] //在Vtable中的函数索引号
 HRESULT QuitCommandMethod (); //退出VC编辑器
};

  在接口ICommands添加接口函数,那么相应的我们也要在类CCommands中声明和实现ICommands接口函数,函数的内部代码和普通工程代码没什么区别。

//Implement(CCommands类内部接口函数的声明)
public:
STDMETHOD(GetCurDirCommandMethod)(THIS);
STDMETHOD(QuitCommandMethod)(THIS);

//Function Code(Ccommands类内部接口函数的实现)
//得到当前VC开发环境的工作目录[您也可以让它成为你想要实现的功能代码]
STDMETHODIMP CCommands::GetCurDirCommandMethod()
{
 AFX_MANAGE_STATE(AfxGetStaticModuleState());
 VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
 BSTR bstrCurDir;
 m_pApplication->get_CurrentDirectory(&bstrCurDir);
 CString str(bstrCurDir);
 ::MessageBox(NULL, str, "VC工作目录", MB_OK | MB_ICONINFORMATION);
 VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
 return S_OK;
}

//退出VC开发环境

STDMETHODIMP CCommands::QuitCommandMethod()
{
 AFX_MANAGE_STATE(AfxGetStaticModuleState());
 VERIFY_OK(m_pApplication->EnableModeless(VARIANT_FALSE));
 if(::MessageBox(NULL,"您想退出VC++编辑器吗(Y/N)?","询问信息...", MB_YESNO | MB_ICONQUESTION) == IDYES)
  m_pApplication->Quit();
  VERIFY_OK(m_pApplication->EnableModeless(VARIANT_TRUE));
 return S_OK;
}

  <3.4> 创建工具栏,连接工具栏按钮事件

  所有的幕后工作已经准备就绪,只差个工具栏界面就一切OK了。打开类CDSAddIn,它里面有三个成员函数,其中OnConnection和OnDisconnection成员函数的意义非常重要。它们的意义如下:

  <1>OnConnection:插件的初始化任务都在这里完成。如COM服务的启动,工具栏/菜单栏的创建,工具栏按钮/菜单项的添加与修改等等。

  <2>OnDisconnection:插件的卸载工作都在这里完成。如COM服务的卸载,工具栏/菜单栏的销毁,释放等等。

  了解了它们各自的用途之后我们就可以在相应的消息事件中添加代码了。很显然工具栏的初始化应该在OnConnection事件中完成。

  在OnConnection事件中系统首先获得了VC应用程序接口,然后调用一个接口函数:AddCommand来为插件添加命令和命令影射函数。然后再使用另外一个接口函数AddCommandBarButton向工具栏中添加工具栏按钮,其中每个工具栏按钮会和一个命令标志符号相连接,这样就能实现按钮和命令(消息)之间的一一对应。下面是添加一个命令和一个工具栏按钮的代码(如果你要添加多个工具栏按钮只要重复此步骤即可):

LPCTSTR szCommand = _T("GetCurDirCommand");
VARIANT_BOOL bRet;
CString strCmdString;
strCmdString.LoadString(IDS_CMD_STRING);
strCmdString = szCommand + strCmdString;
CComBSTR bszCmdString(strCmdString);
CComBSTR bszMethod(_T("GetCurDirCommandMethod"));

CComBSTR bszCmdName(szCommand); //和下面添加工具栏按钮对应

VERIFY_OK(pApplication->AddCommand(bszCmdString,bszMethod,0,dwCookie,&bRet));
//AddCommand 参数含义:
//bszCmdString:命令字符串。
//bszMethod:Icommands接口函数名。
//第三个参数代表位图偏移量。
//第四和第五个参数分贝为系统参数和返回值(参照MSDN的IApplication介绍)

if (bRet == VARIANT_FALSE)
{
 *OnConnection = VARIANT_FALSE;
 return S_OK;
}

//添加工具栏按钮
if (bFirstTime == VARIANT_TRUE)
{
 VERIFY_OK(pApplication->AddCommandBarButton(dsGlyph, bszCmdName, m_dwCookie));
}

  <3.5> 编译,连接及在VC中引入插件

  以上就是我们所有的代码工作,接下来赶快Build以下吧。编译通过的话,在你的工程Debug目录下会有个dll文件。然后打开VC编辑器,在VC任何一个工具栏上点击鼠标右键,弹出如下图所示菜单。然后选择”Customize”子菜单,打开如下图所示的工具栏定制窗口:


  接着选择该窗口的最后一页"Add-Ins and Macro Files"出现下图所示窗口。


  然后点击”Browse...”按钮,这时打开你工程下的Debug目录中的DLL文件,这样你就可以看到你制作的工具栏了。同样你再次打开上面的菜单,这次可以看到多了一个工具栏,并且名字乱七八糟的,怎么改变工具栏的名字呢?方法很简单:打开上面窗口中的”Toolbars”选项页,在工具栏列表框中找到你的工具栏,然后在”Toolbar name”编辑框中输入你想要的名字即可。再打开上面的菜单看看名字是不是变了,哈哈!


  OK,今天的话题就聊到这里。

posted @ 2006-09-30 22:58 Coolfiry 阅读(267) | 评论 (0)编辑 收藏

  插件式设计近年来非常流行,其中eclipse起了推波助澜的作用,提到插件式就会不由自主的想到eclipse。其实插件式设计并不是什么新事物,早在几十年前就有了。像X Server就是基于插件式设计的,除了核心功能外,它所有的扩展功能和设备驱动都是以插件方式加入进来的。

  基于插件的设计好处很多:把扩展功能从框架中剥离出来,降低了框架的复杂度,让框架更容易实现。扩展功能与框架以一种很松的方式耦合,两者在保持接口不变的情况下,可以独立变化和发布。公开插件接口,让第三方有机会扩展应用程序的功能,有财大家一起发。另外,还可以让开源与闭源共存于一套软件,你的插件是开源还是闭源,完全由你自己决定。

  基于插件设计并不神秘,相反它比起一团泥的设计更简单,更容易理解。各种基于插件设计的架构都有自己的特色,但从总体架构上看,其模型都大同小异。这里我们介绍一个简单的模型,并给出几个实例,希望对新手有所启发。

  1. 基本架构

plugin.jpg

  插件式设计的应用程序,基本上可以用上图来表示。当然,此图是一种较高层次的表示,实际的设计会更复杂一些。我们在这里为了阐述方便,不用故意搞得那么复杂。

  应用程序由应用程序框架、插件接口、插件和公共函数库四部分组成。

  应用程序框架负责应用程序的整体运作,它清楚程序整个流程,但并不知道每个过程具体要做什么。它在适当的时候调用一些插件,来完成真正的功能。

  插件接口是一个协议,可能用IDL描述,可能是头文件,也可能一段文字说明。插件按照这个协议实现出来,就可以加入到应用程序中来。当然,对于复杂的系统,插件接口可能有多个,各自具有独立的功能。

  插件是完成实际功能的实体,实现了要求的插件接口。尽管实现什么以及怎么实现,完全是插件自己的自由。在实际情况来,一般还是有些限制,因为插件接口本身可能就是一个限制。如,实现编译功能的插件,自然不能实现成一个聊天功能的插件。

  公共函数库是一组函数或者类,应用程序框架和插件都可以调用。它通常是一个独立的动态库(DLL)。应用程序框架本身是公用的,是代码复用的一种方式。但并不是所有可复用代码都可以放在框架中,特别是插件会用到的公共代码,那会造成插件对框架的依赖。把这些公共代码提取到一个独立的库中,是一种好的方法。

  另外,值得补充说明一下的是插件接口。插件接口通常有两种:

  通用插件接口:这一类插件接口是通用的,你无法从接口函数看出这个插件的功能。它的接口函数通常有这些函数:

  init : 用于初始化插件,通常在插件被加载时调用。

  deinit:用于反初始化插件,通常在插件被卸载时调用。

  run:让插件起动。

  stop:让插件停止。

  至于插件要完成什么功能,要插到哪里,在init函数里决定,它调用公共函数库里的函数把自己注册到框架中某个位置。

  专用插件接口:这一类插件接口是专用的,看到它的接口函数说明,你就可以大致了解它的功能了。

  加入插件的方式通常采用配置信息来实现,配置信息可以是注册表,也可以配置文件。也可以动态注册进来,或者把插件放到指定的位置。

  下面我们来看几个实例:

  2. 桌面设计

  最近一段时间完成了桌面模块的设计和实现。按照以往的经验,桌面模块通常是变化最多的一个模块,SPEC总是在不断的调整的效果,不同客户要求实现具有个性化的桌面,直到产品快发布了,桌面的SPEC还在不停的修改。另外,在智能手机中,桌面占有特殊的地位,很多东西都可能往桌面里塞,桌面不但是各种功能的大杂烩,还是一些系统消息的中转站。

  这个任务比较棘手,所以在设计时就分外小心。首先想到的就是采用插件式设计,把外围功能独立出来,尽量简化框架的实现。

  插件:每一个最小功能单元都是一个插件,它可以是可见的,也可以是不可的,也可以是动态变化的。比如时间、电池电量、网络连接、信号强弱、新事件(如SMS、MMS、EMAL、ALARM和未接电话等)、应用程序快捷方式、左右操作按钮和其它处理系统事件的功能单元。每个插件都用一个.desktop来描述,这是遵循freedesktop.org的标准的。

  桌面框架包括:状态栏、开始菜单、操作栏、桌面区、事件管理器和主题管理器。而状态栏、开始菜单、操作栏、桌面区和事件管理器都是容器,容纳各种插件。对于可见的插件,可以有自己的表现方式,也可以采用通用的表现方式。

  公共函数库:一些抽象的类、实现插件的辅助类以及其它一些可能被公用的类。

  插件接口:对于不可见的插件要求实现事件处理功能,可见的插件还要求实现绘制功能。

  3. 模拟器设计

  一个同事负责设计另外一个平台的PC模拟环境设计。在我的建议下,他对架构作了调整。调整后的架构非常简单,也可以认为是插件式的设计,它由下面几部分组成:

  应用程序框架:负责模拟器基本功能,如模拟键盘和显示设备、换肤功能等。

  插件:就是被模拟的平台,如microwindow及相应的手机应用程序。尽管运行时通常只有一个插件运行,这样做仍然有意义,如果要换成minigui或者其它平台时,模拟器不需要作任何修改。

  公共函数库:它由应用程序框架初始化一些信息和回调函数,然后供插件(即microwindow)调用,插件利用它来实现显示和输入等驱动程序。

  插件接口:如起动和停止模拟平台等。

  4. GIMP

  GIMP是一个功能强大的图形图像编辑器,典型的基于插件式的设计,在《unix编程艺术》中,作为插件式设计示例介绍过。

  应用程序框架:GUI

  插件:完成图像的各种转换和处理功能,如模糊、去斑和色彩调整等。

  公共函数库:放在libgimp.so里。

  插件接口:对GIMP感兴趣的朋友,可以到官方网站上去阅读更多的文档。

posted @ 2006-09-30 22:57 Coolfiry 阅读(699) | 评论 (0)编辑 收藏

  Google推荐的开发环境是VS 2003,GoogleDesktop的插件是基于COM的,而COM是语言无关的,所以你可以用任何能开发COM的工具(语言)开发。

  如果你使用的VS 2003或者VS 2005,建立开发环境非常容易。不过,如果你像我一样恋旧,还是喜爱VC6的简洁快速,排斥庞大缓慢的VS 2003或者VS 2005,可能就要费一点周折了。

  这里只讨论VC6的环境设置。

  Google没有为VC6 提供开发向导,也就是说,所有代码你都得手工就编写。如果是出于学习的目的,手工去写这些代码,付出的劳动会有所回报的。另外,VC6所带的ATL版本也有点老,一些类只有在新版本中才有,在VC6中无法使用,所以有时你不得不面对一些COM的细节问题。同样,同样如果出于学习的目的,所花费的时间也是值得的。

  建立开发环境的第一步就是下载GoogleDesktop的SDK,下载地址为http://desktop.google.com/。

  解开之后,GD_SDK\api目录下有下面几个目录:

documentation
samples
tools
wizards

  建议先大概看一下documentation中的文档,然后阅读samples中的部分代码,找一下感觉。

  GoogleDesktop提供全部接口都在三个IDL文件中声明:

GoogleDesktopActionAPI.idl
GoogleDesktopAPI.idl
GoogleDesktopDisplayAPI.idl

  开发GoogleDesktop的插件,有以上文件已经足够(当然你要安装GoogleDesktop本身)了。但是C++中不能直接使用idl文件,要通过midl.exe编译成头文件,才能使用。其实不用这么麻烦,GD_SDK\api\samples\common目录中已经有相关头文件了:

GoogleDesktopDisplayAPI.h

GoogleDesktopComponentRegistration.h

GoogleDesktopAPI.h

GoogleDesktopActionAPI.h

  直接使用这几个头文件,可以省去用midl编译步骤。只要修改VC6的设置,让它可以找到上述头文件就行了。有两种方式可以做到这一点。一种方式是针对当前项目的:

  1. 打开菜单Project->Settings

  2. 打开属性页的C/C++标签

  3. 选择Categary的Preprocessor项

  4. 在Additional Include directories一栏加入上述文件所在的目录

  另一种方式是针对VC6所有的项目的:

  1. 打开菜单Tool->Options…

  2. 打开属性页的Directories标签

  3. 选择Show directories for中的include files项

  4. 在Directories中加上述文件所在的目录

  至于选择哪一种方式,完全看你个人爱好,后者会方便一点,对懒人比较适用,但它会影响所有的VC6项目,或许会有某些副作用。

posted @ 2006-09-30 22:55 Coolfiry 阅读(242) | 评论 (0)编辑 收藏

 

原文地址:http://www.blogjava.net/BlueDavy/archive/2006/05/28/48593.html

摘要:插件开发框架其实和目前开源界流行的MVC框架之类的相同,都决定了基于这个框架的开发方式,如基于MVC框架,就会按照MVC思想来进行开发,而插件开发框架呢,也是同样如此,就要求基于插件的方式来进行开发,不过插件开发框架和MVC框架又有不同,插件开发框架是一个可以成为系统基础架构的框架,而MVC框架通常来讲不足以成为,如在目前的MVC框架Webwork、Struts上我们通常都需要加上Spring、Hibernate来构成系统完整的基础架构,这个时候由于MVC框架的实现是没有标准可参照的,就造成了在各种系统中形成了不同的但很类似的基础架构,但却造成了无法复用的现象;插件开发框架则是作为统一系统基础架构的一种开发方式,它使得系统的复用成为了可能,而同时由于插件开发框架对于动态性的支持,使得系统更加的灵活和可扩展。来看看一个插件开发框架,应该提供些什么东西,作为改变系统架构思想的框架,插件框架需要考虑很多方面,如开发、测试、部署等,总结下来一个插件框架应提供插件的开发规范;插件开发、调试的IDE;

posted @ 2006-09-30 22:53 Coolfiry 阅读(265) | 评论 (0)编辑 收藏

     摘要: N皇后问题是一个典型的需要用回溯算法来解决的问题。回溯算法可以用递归方法来实现,也可以用非递归方法来实现。用递归的方法来解决回溯的问题思路很清晰,但是耗费的内存资源较多,速度也较慢;非递归方法具有速度快和耗费较少内存资源的优点,但是程序的逻辑结构却很复杂——不过搞懂之后觉得也很简单。   在写非递归算法之前,参考了网上的一些文章,但是觉得那些程序都很晦涩难懂,而且存在一些问题,我索性自己写了一个,...  阅读全文

posted @ 2006-09-27 22:20 Coolfiry 阅读(461) | 评论 (0)编辑 收藏

烦的很啊,但要认认真真做人,兢兢业业做事哦

posted @ 2006-09-27 22:15 Coolfiry 阅读(260) | 评论 (0)编辑 收藏

仅列出标题
共4页: 上一页 1 2 3 4 下一页