jar文件的复制和解压(JarInputStream,JarOutputStream和JarFile)

  • Post author:
  • Post category:其他


需求1:解压某个jar文件输出到某个文件夹。

需求2:对某个文件夹进行打包,生成一个jar文件。

需求3:复制某个jar文件,生成另一个jar文件,jar的内容可能需要进行更改比如做加密等操作。

直接上代码:


import java.io.InputStream;
import java.io.OutputStream;
import java.util.jar.JarEntry;

/**
 * jar处理器
 */
@FunctionalInterface
public interface JarFileHandler{

    /**
     * 处理jar
     * 注意:在此处对inputStream的字节流进行加密后,调用closeEntry()时会抛异常:
     * java.util.zip.ZipException: invalid entry size (expected 7260 but got 7264 bytes)
     * at java.util.zip.ZipOutputStream.closeEntry(ZipOutputStream.java:262)
     * @param jarEntry jar条目
     * @param inputStream 输入流
     * @param outputStream 输出流
     * @throws
     */
    OutputStream handle(JarEntry jarEntry, InputStream inputStream, OutputStream outputStream) throws Exception;

}


import java.io.InputStream;
import java.io.OutputStream;
import java.util.jar.JarEntry;

/**
 * 默认jar处理器,不做任何处理
 */
public class DefaultJarFileHandler implements JarFileHandler{

    /**
     * 默认jar处理器
     */
    private static final JarFileHandler defaultJarFileHandler = new DefaultJarFileHandler();

    private DefaultJarFileHandler(){}

    /**
     * 获取默认jar处理器
     * @return
     */
    public static JarFileHandler getInstance(){
        return defaultJarFileHandler;
    }

    @Override
    public OutputStream handle(JarEntry jarEntry, InputStream inputStream, OutputStream outputStream)  throws Exception{
        return JarUtil.write(inputStream,outputStream);
    }

}

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * File处理器
 */
@FunctionalInterface
public interface FileHandler {

    /**
     * 处理文件
     * @param file 文件
     * @param inputStream 输入流
     * @param outputStream 输出流
     * @throws
     */
    OutputStream handle(File file, InputStream inputStream, OutputStream outputStream) throws Exception;

}

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 默认File处理器,不做任何处理
 */
public class DefaultFileHandler implements FileHandler{

    /**
     * 默认File处理器
     */
    private static final DefaultFileHandler defaultFileHandler = new DefaultFileHandler();

    private DefaultFileHandler(){}

    /**
     * 获取默认File处理器
     * @return
     */
    public static FileHandler getInstance(){
        return defaultFileHandler;
    }

    @Override
    public OutputStream handle(File file, InputStream inputStream, OutputStream outputStream)  throws Exception{
        return JarUtil.write(inputStream,outputStream);
    }

}

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;

/**
 * 加密File处理器
 */
public class EncryptFileHandler implements FileHandler{

    /**
     * 需要加密的class文件所在package
     */
    private List<String> encryptPackages = Arrays.asList("BOOT-INF/classes/指定的包名1","BOOT-INF/classes/指定的包名2");

    @Override
    public OutputStream handle(String parentPath, File file, InputStream inputStream, OutputStream outputStream)  throws Exception{
        parentPath = parentPath.replaceAll("\\\\","/")+"/";
        String name = file.getAbsolutePath().substring(parentPath.length()).replaceAll("\\\\","/");
        if(name.endsWith(".class")){
            for (String encryptPackage : encryptPackages) {
                if(name.startsWith(encryptPackage)){
                    System.out.println("加密:"+name);
                    CipherService cipherService = new DesCipherServiceImpl();
                    byte[] data = FileUtil.readData(inputStream);
                    byte[] encrypt = cipherService.encrypt(data);
                    outputStream.write(encrypt, 0, encrypt.length);
                    return outputStream;
                }
            }
        }
        return JarUtil.write(inputStream,outputStream);
    }

}

/**
 * 加解密处理器
 */
public interface CipherService {

    /**
     * 加密
     * @param data
     * @return
     */
    byte[] encrypt(byte[] data);

    /**
     * 解密
     * @param data
     * @return
     */
    byte[] decrypt(byte[] data);
}


import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.SecureRandom;

public class DesCipherServiceImpl implements CipherService {

    private static final byte[] DES_KEY = "12345678".getBytes();

    @Override
    public byte[] encrypt(byte[] data) {
        try {
            // DES算法要求有一个可信任的随机数源
            SecureRandom sr = new SecureRandom();
            DESKeySpec deskey = new DESKeySpec(DES_KEY);
            // 创建一个密匙工厂,然后用它把DESKeySpec转换成一个SecretKey对象
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey key = keyFactory.generateSecret(deskey);
            // 加密对象
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, key, sr);
            // 加密
            return cipher.doFinal(data);
        } catch (Exception e) {
            throw new RuntimeException("加密错误,错误信息:", e);
        }
    }

    @Override
    public byte[] decrypt(byte[] data) {
        try {
            // DES算法要求有一个可信任的随机数源
            SecureRandom sr = new SecureRandom();
            DESKeySpec deskey = new DESKeySpec(DES_KEY);
            // 创建一个密匙工厂,然后用它把DESKeySpec转换成一个SecretKey对象
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey key = keyFactory.generateSecret(deskey);
            // 解密对象
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.DECRYPT_MODE, key, sr);
            // 解密
            return cipher.doFinal(data);
        } catch (Exception e) {
            throw new RuntimeException("解密错误,错误信息:", e);
        }
    }

}

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;

public class JarUtil {

    /**
     * 解压jar
     * @param sourceJarFile 原jar
     * @param targetDir 解压路径
     * @throws Exception
     */
    public static void unPackageJar(File sourceJarFile,File targetDir) throws Exception{
        if(!sourceJarFile.exists()){
            System.err.println("文件"+sourceJarFile.getAbsolutePath()+"不存在");
            return;
        }

        URL url = new URL("jar:file:" + sourceJarFile.getAbsolutePath() + "!/");
        JarURLConnection uc = (JarURLConnection) url.openConnection();
        JarFile jarFile = uc.getJarFile();
        Enumeration<JarEntry> entries = jarFile.entries();
        while (entries.hasMoreElements()) {
            JarEntry jarEntry = entries.nextElement();
            String name = jarEntry.getName();
            File path = new File(targetDir.getAbsolutePath() +File.separatorChar + name);
            if (jarEntry.isDirectory()) {
                if(path.exists()){
                    System.err.println("路径已存在:"+path.getAbsolutePath());
                    return;
                }else {
                    boolean mkdirs = path.mkdirs();
                    if (!mkdirs) {
                        System.err.println("创建路径失败:" + path.getAbsolutePath());
                        return;
                    }
                }
            } else {
                System.out.println("读取文件:"+name);
                InputStream inputStream = jarFile.getInputStream(jarEntry);
                FileOutputStream fos = null;
                try {
                	File parentDir = path.getParentFile();
                    if(!parentDir.exists()){
                        boolean mkdirs = parentDir.mkdirs();
                        if (!mkdirs) {
                            System.err.println("创建路径失败:" + parentDir.getAbsolutePath());
                            return;
                        }
                    }
                    fos = new FileOutputStream(path);
                    write(inputStream, fos);
                    System.out.println("拷贝文件成功:"+path.getAbsolutePath());
                }catch (Exception e){
                    System.err.println("拷贝文件失败:"+path.getAbsolutePath());
                }finally {
                    if(fos!=null){
                        fos.close();
                    }
                }
            }
        }
    }

    /**
     * 打包jar
     * @param sourceDir 原文件夹
     * @param targetJarFile 目标jar
     * @param handler  File处理器,可为null
     * @throws Exception
     */
    public static void packageJar(File sourceDir,File targetJarFile, FileHandler handler) throws Exception{
        if(!sourceDir.exists()){
            System.err.println("文件夹"+sourceDir.getAbsolutePath()+"不存在");
            return;
        }
        File[] files = sourceDir.listFiles();
        if(files==null||files.length==0){
            System.err.println("文件夹"+sourceDir.getAbsolutePath()+"为空");
            return;
        }
        if(handler==null){
            handler = DefaultFileHandler.getInstance();
        }
        String parentPath = sourceDir.getAbsolutePath();
        JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(targetJarFile));
        try {
            for (File file : files) {
                packageJar(parentPath,file,jarOutputStream,handler);
            }
        }finally {
            jarOutputStream.close();
        }
    }

    /**
     * 递归遍历文件和文件夹,并打包
     * @param parentPath 父文件夹
     * @param file 文件或文件夹
     * @param jarOutputStream 输出流
     * @param handler File处理器,可为null
     * @throws Exception
     */
    private static void packageJar(String parentPath,File file,JarOutputStream jarOutputStream,FileHandler handler) throws Exception{
        String absolutePath = file.getAbsolutePath();

        if (file.isDirectory()) {
            // jarName必须以/结尾,否则打包后是文件,而不是文件夹
            String jarName = absolutePath.substring(absolutePath.indexOf(parentPath)+parentPath.length()+1)+"/";
            ZipEntry jarEntry = new JarEntry(jarName);
            jarOutputStream.putNextEntry(jarEntry);
            jarOutputStream.closeEntry();
            System.out.println("打包文件夹成功:"+jarName);
            File[] childFiles = file.listFiles();
            if(childFiles==null||childFiles.length==0){
                return;
            }else{
                for (File childFile : childFiles) {
                    packageJar(parentPath,childFile,jarOutputStream,handler);
                }
            }
        } else {
            String jarName = absolutePath.substring(absolutePath.indexOf(parentPath)+parentPath.length()+1);
            ZipEntry jarEntry = new JarEntry(jarName);
            System.out.println("读取文件:"+jarName);
            jarOutputStream.putNextEntry(jarEntry);
            InputStream inputStream = new FileInputStream(file);
            handler.handle(file,inputStream,jarOutputStream);
            jarOutputStream.closeEntry();
            System.out.println("打包文件成功:"+jarName);
        }
    }

    /**
     * 读取原jar,拷贝所有内容到另一个jar
     * @param sourceJarFile 原jar
     * @param targetJarFile 目标jar
     * @param handler jar处理器,可为null
     * @throws Exception
     */
    @Deprecated
    public static void copyJar(File sourceJarFile, File targetJarFile, JarFileHandler handler) throws Exception{
        if(!sourceJarFile.exists()){
            System.err.println("文件"+sourceJarFile.getAbsolutePath()+"不存在");
            return;
        }
        if(handler==null){
            handler = DefaultJarFileHandler.getInstance();
        }
        JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(targetJarFile));
        try {
            URL url = new URL("jar:file:" + sourceJarFile.getAbsolutePath() + "!/");
            JarURLConnection uc = (JarURLConnection) url.openConnection();
            JarFile jarFile = uc.getJarFile();
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry jarEntry = entries.nextElement();
                String name = jarEntry.getName();
                if (jarEntry.isDirectory()) {
                    jarOutputStream.putNextEntry(jarEntry);
                    jarOutputStream.closeEntry();
                    System.out.println("拷贝文件夹成功:"+name);
                } else {
                    System.out.println("读取文件:"+name);
                    jarOutputStream.putNextEntry(jarEntry);
                    InputStream inputStream = jarFile.getInputStream(jarEntry);
                    handler.handle(jarEntry,inputStream,jarOutputStream);
                    jarOutputStream.closeEntry();
                    System.out.println("拷贝文件成功:"+name);
                }
            }
        }finally {
            jarOutputStream.close();
        }
    }

    /**
     * 从输入流读数据,写入到输出流
     * @param inputStream 输入流
     * @param outputStream 输出流
     * @return
     * @throws Exception
     */
    public static OutputStream write(InputStream inputStream, OutputStream outputStream) throws Exception {
        try {
            int len = 0;
            byte[] b = new byte[1024];
            while ((len = inputStream.read(b)) > 0) {
                outputStream.write(b, 0, len);
            }
            outputStream.flush();
        }finally {
            if(inputStream!=null){
                inputStream.close();
            }
        }
        return outputStream;
    }

}

import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;

public class Test1 {

    @Test
    public void writeJarEntryTest() throws Exception{
        JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream("D:\\myworkspace\\out.jar"));

        //加进一个jar文件
        jarOutputStream.putNextEntry(new JarEntry("aaa.jar"));
        JarUtil.write(new FileInputStream(new File("D:\\myworkspace\\aaa.jar")),jarOutputStream);
        jarOutputStream.closeEntry();
        //加进一个jar文件
        jarOutputStream.putNextEntry(new JarEntry("bbb.jar"));
        JarUtil.write(new FileInputStream(new File("D:\\myworkspace\\bbb.jar")),jarOutputStream);
        jarOutputStream.closeEntry();
        //加进一个xml文件
        jarOutputStream.putNextEntry(new JarEntry("pom.xml"));
        JarUtil.write(new FileInputStream("D:\\myworkspace\\pom.xml"),jarOutputStream);
        jarOutputStream.closeEntry();
        //加进一个文件夹
        jarOutputStream.putNextEntry(new JarEntry("testpackage/"));
        jarOutputStream.closeEntry();

        jarOutputStream.close();
    }

    @Test
    public void unPackageJarTest() throws Exception {
        JarUtil.unPackageJar(new File("D:\\myworkspace\\aaa.jar"),
                new File("D:\\myworkspace\\aaa"));
    }

    @Test
    public void copyJarTest() throws Exception {
        JarUtil.copyJar(new File("D:\\myworkspace\\aaa.jar"),
                new File("D:\\myworkspace\\aaa2.jar"),null);
    }
    
	@Test
    public void packageJarTest() throws Exception {
        JarUtil.packageJar(new File("D:\\myworkspace\\aaa\\"),
                new File("D:\\myworkspace\\aaa.jar"),null);
    }

}



版权声明:本文为u013813491原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。