zoukankan      html  css  js  c++  java
  • Java如何快速修改Jar包里的文件内容

    需求背景:写了一个实时读取日志文件以及监控的小程序,打包成了Jar包可执行文件,通过我们的web主系统上传到各个服务器,然后调用ssh命令执行。每次上传前都要通过解压缩软件修改或者替换里面的配置文件,这样感觉有点麻烦,就想办法能不能通过程序动态生成配置文件,然后修改或者替换掉Jar包里的配置文件,最后再上传到各个服务器去执行。   

    实现历程:刚开始看了大量文章,整理出来了一个操作Jar包的工具类,用工具类里面的方法去修改一个30M左右的Jar包文件时,发现耗时竟然要7秒,而且修改Jar文件的方法确实有点复杂(这个可能需要开发JDK的专业人士提供简单、高效的方法了),果断忍受不了,然后想能不能通过其他的方法来实现。想到了一个方案,就是不通过java去修改Jar里的文件,而是用linux的Jar命令(当然也是通过java去调用linux命令),先解压缩jar包,然后将动态生成的配置文件替换解压缩包里的配置文件,最后再将目录压缩成Jar文件。经过测试,这样大概需要4秒的时间,确实快了不少。想了很久也没有想到其他更好的办法,正打算实施的时候,看到了这条命令:jar uf test.jar manifest.mf  -u 更新已存在的 JAR 文件包 (添加文件到 JAR 文件包中)  -f 指定 JAR 文件名;瞬间来了灵感,直接调用这条命令不就OK了!通过这条命令几秒钟就轻轻松松搞定了,简直是山穷水尽疑无路,柳暗花明又一村。

    下面是我整理的操作Jar包的工具类(已经通过测试,可以拿去直接用),包括读取Jar包的文件内容,遍历 Jar包,修改 Jar包文件内容等操作,供大家参考。

      1 package com.agent.util;
      2 
      3 import java.io.BufferedReader;
      4 import java.io.ByteArrayOutputStream;
      5 import java.io.FileNotFoundException;
      6 import java.io.FileOutputStream;
      7 import java.io.IOException;
      8 import java.io.InputStream;
      9 import java.io.InputStreamReader;
     10 import java.util.Enumeration;
     11 import java.util.Iterator;
     12 import java.util.Map;
     13 import java.util.Set;
     14 import java.util.TreeMap;
     15 import java.util.jar.JarEntry;
     16 import java.util.jar.JarFile;
     17 import java.util.jar.JarOutputStream;
     18 
     19 
     20 public class JarUtil {
     21 
     22     /**
     23      * 读取jar包所有的文件内容,显示JAR文件内容列表
     24      * @param jarFileName
     25      * @throws IOException
     26      */
     27     public static void readJARList(String jarFilePath) throws IOException {
     28         // 创建JAR文件对象 
     29         JarFile jarFile = new JarFile(jarFilePath);
     30         // 枚举获得JAR文件内的实体,即相对路径
     31         Enumeration en = jarFile.entries();
     32         System.out.println("文件名	文件大小	压缩后的大小");
     33        // 遍历显示JAR文件中的内容信息 
     34         while (en.hasMoreElements()) {
     35             // 调用方法显示内容 
     36             process(en.nextElement());
     37         }
     38     }
     39 
     40     // 显示对象信息
     41     private static void process(Object obj) {
     42         // 对象转化成Jar对象
     43         JarEntry entry = (JarEntry) obj;
     44         // 文件名称
     45         String name = entry.getName();
     46         // 文件大小 
     47         long size = entry.getSize();
     48         // 压缩后的大小 
     49         long compressedSize = entry.getCompressedSize();
     50         System.out.println(name + "	" + size + "	" + compressedSize);
     51     }
     52 
     53     /**
     54      * 读取jar包里面指定文件的内容
     55      * @param jarFileName jar包文件路径
     56      * @param fileName  文件名
     57      * @throws IOException
     58      */
     59     public static void readJarFile(String jarFilePath,String fileName) throws IOException{
     60         JarFile jarFile = new JarFile(jarFilePath);
     61         JarEntry entry = jarFile.getJarEntry(fileName);
     62         InputStream input = jarFile.getInputStream(entry);
     63         readFile(input);
     64         jarFile.close();
     65     }
     66 
     67 
     68     public static void readFile(InputStream input) throws IOException{
     69         InputStreamReader in = new InputStreamReader(input);
     70         BufferedReader reader = new BufferedReader(in);
     71         String line ;
     72         while((line = reader.readLine())!=null){
     73             System.out.println(line);
     74         }
     75         reader.close();
     76     }
     77 
     78     /**
     79      * 读取流
     80      *
     81      * @param inStream
     82      * @return 字节数组
     83      * @throws Exception
     84      */
     85     public static byte[] readStream(InputStream inStream) throws Exception {
     86         ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
     87         byte[] buffer = new byte[1024];
     88         int len = -1;
     89         while ((len = inStream.read(buffer)) != -1) {
     90             outSteam.write(buffer, 0, len);
     91         }
     92         outSteam.close();
     93         inStream.close();
     94         return outSteam.toByteArray();
     95     }
     96 
     97     /**
     98      * 修改Jar包里的文件或者添加文件
     99      * @param jarFile jar包路径
    100      * @param entryName 要写的文件名
    101      * @param data   文件内容
    102      * @throws Exception
    103      */
    104     public static void writeJarFile(String jarFilePath,String entryName,byte[] data) throws Exception{
    105 
    106         //1、首先将原Jar包里的所有内容读取到内存里,用TreeMap保存
    107         JarFile  jarFile = new JarFile(jarFilePath);
    108         //可以保持排列的顺序,所以用TreeMap 而不用HashMap
    109         TreeMap tm = new TreeMap();
    110         Enumeration es = jarFile.entries();
    111         while(es.hasMoreElements()){
    112             JarEntry je = (JarEntry)es.nextElement();
    113             byte[] b = readStream(jarFile.getInputStream(je));
    114             tm.put(je.getName(),b);
    115         }
    116 
    117         JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFilePath));
    118         Iterator it = tm.entrySet().iterator();
    119         boolean has = false;
    120 
    121         //2、将TreeMap重新写到原jar里,如果TreeMap里已经有entryName文件那么覆盖,否则在最后添加
    122         while(it.hasNext()){
    123             Map.Entry item = (Map.Entry) it.next();
    124             String name = (String)item.getKey();
    125             JarEntry entry = new JarEntry(name);
    126             jos.putNextEntry(entry);
    127             byte[] temp ;
    128             if(name.equals(entryName)){
    129                 //覆盖
    130                 temp = data;
    131                 has = true ;
    132             }else{
    133                 temp = (byte[])item.getValue();
    134             }
    135             jos.write(temp, 0, temp.length);
    136         }
    137 
    138         if(!has){
    139             //最后添加
    140             JarEntry newEntry = new JarEntry(entryName);
    141             jos.putNextEntry(newEntry);
    142             jos.write(data, 0, data.length);
    143         }
    144         jos.finish();
    145         jos.close();
    146 
    147     }
    148 
    149 
    150     /**
    151      * 测试案例
    152      * @param args
    153      * @throws Exception
    154      */
    155     public static void main(String args[]) throws Exception{
    156 
    157         //
    158         readJarFile("D:\esjavaclient-0.0.1-SNAPSHOT.jar","es-info.properties");
    159 
    160         String data = "helloBabydsafsadfasdfsdafsdgasdgweqtqwegtqwfwefasdfasfadfasf";
    161 
    162         long start = System.currentTimeMillis();
    163 
    164         writeJarFile("D:\esjavaclient-0.0.1-SNAPSHOT.jar","es-info.properties",data.getBytes());
    165 
    166         long end = System.currentTimeMillis();
    167 
    168         System.out.println(end-start);
    169 
    170         readJarFile("D:\esjavaclient-0.0.1-SNAPSHOT.jar","es-info.properties");
    171 
    172     }
    173 
    174 }

    上面有个测试案例,测试读取其中一个配置文件,然后修改这个文件,最后再读取出来。 一个30M左右的Jar包文件耗时7秒多,实在忍受不了。网上找了很多文章,同时看了Zip相关的源码,也木有找到可以直接修改Jar包文件内容的方法。 最后只能另辟蹊径,找到了一个执行效率非常快的方法。

    关于工具类没有删除文件的方法,大家根据修改的方法稍微改造一下即可。

    工具类参考的博客:

    http://blog.csdn.net/young_kim1/article/details/50482398

    http://javasam.iteye.com/blog/1486803


    如何快速修改Jar包里的文件内容:

    贴出来我巧妙实现的代码:(如果不知道Java 如何调用linux命令的同学,请先补习一下这方面的知识)

      1        String cmd = "jar uf esjavaclient-0.0.1-SNAPSHOT.jar config.properties";
      2         String[] cmds = {"/bin/sh","-c",cmd};
      3         Process pro;
      4         try {
      5             pro = Runtime.getRuntime().exec(cmds);
      6             pro.waitFor();
      7             InputStream in = pro.getInputStream();
      8             BufferedReader read = new BufferedReader(new InputStreamReader(in)); String line = null; while((line = read.readLine())!=null){ System.out.println(line); } } catch (Exception e) { // TODO Auto-generated catch block  e.printStackTrace(); } 

    通过执行这条条命令,就可以很快将我们生成的配置文件config.properties覆盖掉Jar里的文件,从而达到修改的目的。

    总结:如果Jar包里的文件不大的话,完全可以用工具类提供的方法去操作Jar包。比较大的话,修改Jar包的方法,推荐用我那个巧妙的方法。

    最后:给开发JDK的专业人士提点建议,关于操作压缩包这方面的API还不够强大,希望后续可以完善一下

    转载于:https://www.cnblogs.com/pfblog/p/7227184.html

    相关资源:用于修改jar文件包路径_java修改jar包文件,jar包文件路径-Java...

    为人:谦逊、激情、博学、审问、慎思、明辨、 笃行
    学问:纸上得来终觉浅,绝知此事要躬行
    为事:工欲善其事,必先利其器。
    态度:道阻且长,行则将至;行而不辍,未来可期
    转载请标注出处!
  • 相关阅读:
    9.27作业
    9.20作业
    9.13作业
    9.6作业
    localstorage,sessionstorage使用
    oracle 客户端重新安装遇到的问题
    HTML5学习笔记(<command>,<details>,<dialog>)
    HTML5学习笔记(HTML5新标签<bdi>)
    html5学习笔记(html5新标签<aside>)
    html5学习笔记(html5新标签<article>)
  • 原文地址:https://www.cnblogs.com/ios9/p/15498342.html
Copyright © 2011-2022 走看看