使用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脚本写好了交互,完成
      

      总结:

      ​ 使用这些命令处理一些简单的类还是很方便的,对于复杂的还是使用开发工具去搞比较合适。

原文地址:https://www.cnblogs.com/yanht/p/14893554.html