压缩文件IO流的使用和简单封装(0213)

分为三个部分: 第一部分 ,先是试用了zipinputstream的用法 第二部分, 是进一步试用了压缩流zipoutputStream和加密的方法 第三部分 , 则是对上述过程封装为一个OOZip类

功能简述: 分为普通的压缩和加密的压缩,对应的解压缩 。普通的压缩:文件和文件夹都可以。 加密的压缩:文件和文件夹都可以,当加密的时候,则生成的zip文件里面的文件打开时乱码,必须用对应的unzipCrypto方法进行解压才有效。当然不会像winzip会提醒你输入密码,可以让你打开,只不过打开的是乱码。

1: 先从com.rupeng.gtk4j挖出了zipInputStream的用法,用于解压缩,测试只能针对zip文件。 于是就有了初始版本的解压缩流:

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
* @author    叶昭良
* @time      2015年2月12日下午1:19:18
* @version   TestZipInputStream V1.0
*/
public class TestZipInputStream
{

        /**
         * @param args
         */
        public static void main(String[] args)
        {
                //unZipShared("e:\\test\\test.zip");
                //unZipShared("e:\\test\\test1.zip");
                //rar暂时无法解压出来,但是zip文件是可以的
                unZipShared("e:\\test\\test1.zip","e:\\testOutput");
        }
        
        /**
         *   解压缩 zip文件,只能限制为rar
         * @param zipName        待解压的zip文件
         * @param outputfolder   解压zip文件到outputFoler文件夹下
         */
        public static void unZipShared(String zipName,String outputfolder)
        {
                File gtkDir = new File(outputfolder);// *.dll放的文件夹
                if (!gtkDir.exists())
                {
                        gtkDir.mkdirs();
                }
                InputStream inStream = null;
                try
                {
                        inStream = new  FileInputStream(zipName);
                } catch (FileNotFoundException e1)
                {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                }
                //InputStream inStream = Utils.class.getResourceAsStream("/gtkshare.zip");
                if (inStream == null)
                {
                        throw new UnsatisfiedLinkError("没找到"+zipName);
                }
                try
                {                        
                        unZip(inStream, gtkDir.toString());
                        System.out.println(gtkDir.toString());
                } catch (IOException e)
                {
                        System.err.println("解压缩gtkshare.zip失败" + toFullString(e));
                }
        }

        /**
         * 把streamToZip这个zip文件流解压到硬盘的destDir文件夹,支持多级目录
         * @param streamToZip
         * @param destDir
         * @throws IOException
         */
        public static void unZip(InputStream streamToZip,String destDir)throws IOException
        {  
                ZipInputStream zipStream = new ZipInputStream(streamToZip);
                try
                {
                        ZipEntry zipEntry = null;
                        //通过zipEntry方式支持多级目录
                        while((zipEntry=zipStream.getNextEntry())!=null)
                        {
        if(zipEntry.isDirectory())
        {
                File dir = new File(destDir,zipEntry.getName());
                if(!dir.exists())
                {
                        dir.mkdirs();
                }
        }
        else
        {
                FileOutputStream fileOutStream = new FileOutputStream(new File(destDir,zipEntry.getName()));
                try
                {
                        copy(zipStream, fileOutStream);
                }
                finally
                {
                        close(fileOutStream);
                }
        }
}
                }
                finally
                {
                        close(zipStream);
                }
                
    }
        /**
         *     从zip文件包中拷贝文件
         * @param inStream       zipEntry的某个文件
         * @param outStream      输出的某个文件流
         * @throws IOException
         */
        static void copy(InputStream inStream, OutputStream outStream)
                        throws IOException
        {
                byte[] buffer = new byte[512 * 1024];// 0.5MB 的缓冲区
                int len;
                while ((len = inStream.read(buffer)) >= 0)
                {
                        outStream.write(buffer, 0, len);
                }
        }
        /**
         *    摘自rupeng.gtk4j   不明白具体的作用    非主要问题
         * @param throwable
         * @return
         */
        static String toFullString(Throwable throwable)
        {
                StringWriter sw = null;
                PrintWriter pw = null;
                try
                {
                        sw = new StringWriter();
                        pw = new PrintWriter(sw);
                        throwable.printStackTrace(pw);
                        return sw.toString();
                } finally
                {
                        close(sw);
                        close(pw);
                }
        }
        /**
         *     让文件流安静的关闭
         * @param closeable   关闭接口
         */
        static void close(Closeable closeable)
        {
                if (closeable != null)
                {
                        try
                        {
                                closeable.close();
                        } catch (IOException e)
                        {

                        }
                }
        }


}

2:后来想着有解压缩,必然也是有着压缩,于是就摆了一下,参考了一篇百度知道文章 2.1 首先加入了zip的方法 2.2 改进了zip方法的文件压缩流的写入过程,利用buffersize 2.3 常使用了文章中的加密过程,添加了加密压缩和加密解压缩的过程 2.4 想着实用命令流来进一步实现 压缩和解压缩的调用,后来弃用,改用封装一个OOZip类来实现

于是就有了下面的升级版的压缩和解压缩的程序:

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Random;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.interfaces.PBEKey;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.SecretKeySpec;


/**
* @author    叶昭良
* @time      2015年2月12日下午5:22:31
* @version   TestZipInputStreamUpdate V1.0  增加了压缩 
*                              V2.0   ZipShared加入了 zosTemp.close(); 修复了 压缩的bug,删掉则无法压缩
*                              V3.0   升级了ZipShared 使用了copy函数。
*                              V4.0   增加了加密压缩 和解加密压缩
*/
public class TestZipInputStreamUpdate
{

        
        /**
         * @param args
         */
        private static final String ALGORITHM = "PBEWithMD5AndDES";
        public static void main(String[] args)
        {
                // TODO Auto-generated method stub
                TestZipInputStreamUpdate tisu = new TestZipInputStreamUpdate();
                //不需要再次加入zip文件后缀了
                //tisu.ZipShared("e://test1222bak","e://test1222");
                
                tisu.ZipSharedCrypto("e://test1222bak", "e://test1222passwdByZhao.zip", "123456");
                tisu.unzipCrypto("e://test1222passwdByZhao.zip","c://laoliang","123456");
        //        tisu.unzipCrypto("e://test1222passwdByZhao.zip","c://laoliang","1234565");
                
                /*
                 *  你正在进入e:\test1222bak文件夹
                        你正在进入e:\test1222bak\test1222文件夹
                        你正在压缩a1.zip
                        你正在压缩test123.txt
                        你正在压缩test124.txt
                        
                        通过这个实验总结了:所有操作系统内部的文件都是文件,无论是普通的文件
                        还是文件夹文件,还是管道文件,还是索引文件,还是设备文件,本质上都是
                        文件,只不过是在文件的头上面增加了一些特殊的标记,比如说你需要在文件夹
                        的路径增加一个\路径标志 反斜杠的道理是一样的。
                 */
                
                /*  这是一个命令流的使用方式::
                 *         if(args.length==2){ 
            String name = args[1]; 
            Zip zip = new Zip(); 

            if(args[0].equals("-zip")) 
            {
                    zipname = args[2];
                    zip.doZip(name); 
            }
                
            else if(args[0].equals("-unzip")) 
            {
                    outputfolder = args[2];
                     zip.unZip(name);          
            }     
        } 
        else{ 
            System.out.println("Usage:"); 
            System.out.println("压缩:java Zip -zip directoryName  zipname"); 
            System.out.println("解压:java Zip -unzip fileName.zip outputfolder"); 
            throw new Exception("Arguments error!"); 
        } 
                 */
        }
        public void ZipShared(String fileinput,String zos)
        {
                try
                {
                        //加入"zip"后缀!
                        ZipOutputStream zosTemp = new ZipOutputStream(new FileOutputStream(zos+"zip"));
                        File fApple = new File(fileinput);
                        ZipShared(fApple,zosTemp,"");
                        try
                        {
                                /// 为什么加入这个就可以????
                                //  不加入这有异常????why   Tell me 
                                zosTemp.close();
                        } catch (IOException e)
                        {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                } catch (FileNotFoundException e)
                {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                
        }
        public  void ZipShared(File fileinput,ZipOutputStream zos,String base)
        {
                //ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outputZipName));
                
                //File fileinput = new File(outputZipName);
if(fileinput.isDirectory())
{
        System.out.println("你正在进入"+fileinput+"文件夹");
        File[] fBanana = fileinput.listFiles();
        try
        {
                //传进一个文件夹标志
                zos.putNextEntry(new ZipEntry(base+"/"));
                //让base加上一个/
                base = base.length()==0?"":base+"/";
                for(int i = 0; i < fBanana.length; i++)
                {
                        ZipShared(fBanana[i],zos,base+fBanana[i].getName());
                }
        } catch (IOException e)
        {
                // TODO Auto-generated catch block
                System.out.println("压缩文件夹失败"+e.getMessage());
        }
        
}else
{
        try
        {
                zos.putNextEntry(new ZipEntry(base));
                FileInputStream fis = new FileInputStream(fileinput);
                //改进写入的方式
                /*int b;
                while((b = fis.read())!= -1)
                {
                        zos.write(b); 
                        //效率很定不高  每一个字符  进行一次缓冲
                        //zos.flush();
                }*/
                copy(fis,zos); //利用汝鹏版的copy函数
                System.out.println("你正在压缩"+fileinput.getName());
                //fis.close();
                
                //zos.close();
        } catch (IOException e)
        {
                // TODO Auto-generated catch block
                System.out.println("压缩文件失败"+e.getMessage());
        } 
        //为什么加入则错误
        /*finally
        {
                try
                {
                        zos.close();
                }catch(IOException e)
                {
                        System.out.println("打开流错误!");
                }
        }*/
                }
        }
        public  void ZipSharedCrypto(String fileinput,String zosFile,String pwd)
        {
                
                try
                {        File f1 = new File(fileinput);
                //采用和ZipShared一样的FileOutputStream
                        ZipOutputStream zos  = null;
                        zos = new ZipOutputStream(new FileOutputStream(zosFile));
                        ZipSharedCrypto(f1,zos,"", pwd);
                        try
                        {
                                zos.close();
                        } catch (IOException e)
                        {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                } catch (FileNotFoundException e)
                {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                System.out.println("成了");
        }
        public  void ZipSharedCrypto(File fileinput,ZipOutputStream zos,String base,String pwd)
        {
if(fileinput.isDirectory())
{
        System.out.println("你正在进入"+fileinput+"文件夹");
File[] fApples = fileinput.listFiles();
//因为ZipEntry的isDirectory()方法中,目录以"/"结尾
try
{        
        zos.putNextEntry(new ZipEntry(base+"/"));
        base = base.length()==0?"":(base+"/");
        //一种比较新型的方式循环读写东西。
        for(File ftemp:fApples)
        {
                ZipSharedCrypto(ftemp,zos,base+ftemp.getName(),pwd);
        }
}catch(IOException e)
{
        System.out.println("文件夹加密压缩失败");
        }
}else
{        
        
        try
        {
                zos.putNextEntry(new ZipEntry(base));
                FileInputStream fis = new FileInputStream(fileinput);
                System.out.println("你正在开始加密压缩"+fileinput+"文件");
        PBEKeySpec keySpec = new PBEKeySpec(pwd.toCharArray());
        SecretKeyFactory keyFactory = null;
        try
        {
                keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        } catch (NoSuchAlgorithmException e)
        {
                // TODO Auto-generated catch block
                e.printStackTrace();
        }
        SecretKey passwordKey = keyFactory.generateSecret(keySpec);
        //生成一个炸弹 进行加密
        byte[] bomb =  new byte[8];
        Random rnd = new Random();
        rnd.nextBytes(bomb);
        int iterations = 100;
        PBEParameterSpec parameterSpec = new PBEParameterSpec(bomb, iterations);
        Cipher cipher = null;
        try
        {
                cipher = Cipher.getInstance(ALGORITHM);
        } catch (NoSuchAlgorithmException
                        | NoSuchPaddingException e)
        {
                // TODO Auto-generated catch block
                e.printStackTrace();
        }
        cipher.init(Cipher.ENCRYPT_MODE, passwordKey,parameterSpec);
        //往输出流 添加炸弹
        zos.write(bomb);
        
        //添加加密的主文件内容  1KB缓存区
        byte[] inputBuffer = new byte[1024];
        int bytesRead = 0;
        //如果没有读到信息则为-1
        while((bytesRead = fis.read(inputBuffer))!= -1)
        {
                //每个缓冲区 进行加密写入
                byte[] output = cipher.update(inputBuffer);
                if(output != null)
                {
                        zos.write(output);
                }
        }
        
        //加密结束语
        byte[] outputFinal =null;
        try
        {
                outputFinal = cipher.doFinal();
        } catch (IllegalBlockSizeException | BadPaddingException e)
        {
                // TODO Auto-generated catch block
                e.printStackTrace();
        }
        if(outputFinal != null)
        {
                zos.write(outputFinal);
        }
        
/*        fis.close();
        zos.flush();
        zos.close();*/
        
        
}catch(InvalidKeySpecException | InvalidKeyException | InvalidAlgorithmParameterException | IOException e)
{
        System.out.println("加密失败");
        }
}
        }
        /**
         *   解压缩 zip文件,只能限制为rar
         * @param zipName        待解压的zip文件
         * @param outputfolder   解压zip文件到outputFoler文件夹下
         */
        public static void unZipShared(String zipName,String outputfolder)
        {
                File gtkDir = new File(outputfolder);// *.dll放的文件夹
                //指定的目录不存在  则创建之
                if (!gtkDir.exists())
                {
                        gtkDir.mkdirs();
                }
                InputStream inStream = null;
                try
                {
                        inStream = new  FileInputStream(zipName);
                } catch (FileNotFoundException e1)
                {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                }
                //InputStream inStream = Utils.class.getResourceAsStream("/gtkshare.zip");
                if (inStream == null)
                {
                        throw new UnsatisfiedLinkError("没找到"+zipName);
                }
                try
                {                        
                        unZip(inStream, gtkDir.toString());
                        System.out.println(gtkDir.toString());
                } catch (IOException e)
                {
                        System.err.println("解压缩gtkshare.zip失败" + toFullString(e));
                }
        }

        /**
         * 把streamToZip这个zip文件流解压到硬盘的destDir文件夹,支持多级目录
         * @param streamToZip
         * @param destDir
         * @throws IOException
         */
        public static void unZip(InputStream streamToZip,String destDir)throws IOException
        {  
                ZipInputStream zipStream = new ZipInputStream(streamToZip);
                try
                {
                        ZipEntry zipEntry = null;
                        //通过zipEntry方式支持多级目录
        while((zipEntry=zipStream.getNextEntry())!=null)
        {
                if(zipEntry.isDirectory())
                {
                        System.out.println("你正在创建文件夹文件 比较特殊");
                        File dir = new File(destDir,zipEntry.getName());
                        //如果指定的目录不存在 则创建之
                        if(!dir.exists())
                        {
                                dir.mkdirs();
                        }
                }
                else
                {
                        FileOutputStream fileOutStream = new FileOutputStream(new File(destDir,zipEntry.getName()));
                        try
                        {
                                copy(zipStream, fileOutStream);
                        }
                        finally
                        {
                                close(fileOutStream);
                        }
                        System.out.println("你正在解压缩压缩"+zipEntry.getName());
                }
        }
}
finally
{
        close(zipStream);
}
                
    }
        /**
         *     从zip文件包中拷贝文件 ,按照0.5MB的缓冲写入文件(默认方式)
         * @param inStream       zipEntry的某个文件
         * @param outStream      输出的某个文件流
         * @throws IOException
         */
        static void copy(InputStream inStream, OutputStream outStream)
                        throws IOException
        {
                byte[] buffer = new byte[512 * 1024];// 0.5MB 的缓冲区
                int len;
                while ((len = inStream.read(buffer)) >= 0)
                {
                        outStream.write(buffer, 0, len);
                }
        }
        /**
         *    摘自rupeng.gtk4j   不明白具体的作用    非主要问题
         * @param throwable
         * @return
         */
        static String toFullString(Throwable throwable)
        {
                StringWriter sw = null;
                PrintWriter pw = null;
                try
                {
                        sw = new StringWriter();
                        pw = new PrintWriter(sw);
                        throwable.printStackTrace(pw);
                        return sw.toString();
                } finally
                {
                        close(sw);
                        close(pw);
                }
        }
        /**
         *     让文件流安静的关闭
         * @param closeable   关闭接口
         */
        static void close(Closeable closeable)
        {
                if (closeable != null)
                {
                        try
                        {
                                closeable.close();
                        } catch (IOException e)
                        {

                        }
                }
        }
        
        // 加密解压缩

/**
         * 功能描述:将压缩文件解压到指定的文件目录下
         * @param zipFileName      压缩文件名称(带路径)
         * @param outputDirectory  指定解压目录
         * @return
         * @throws Exception
         */
        public  void unzipCrypto(String zipFileName, String outputDirectory, String pwd)
        {
                ZipInputStream inputStream;
                try
                {
                        inputStream = new ZipInputStream(new FileInputStream(zipFileName));
                        unzipCrypto(inputStream, outputDirectory, pwd);
                } catch (Exception e)
                {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                
        }


        public  void unzipCrypto(ZipInputStream inputStream, String outputDirectory, String pwd) throws Exception
        {
                ZipEntry zipEntry = null;
                FileOutputStream outputStream = null;
                try{
                        while ((zipEntry = inputStream.getNextEntry()) != null) 
                        {
if (zipEntry.isDirectory())
{
        System.out.println("你正在进入"+zipEntry.getName()+"文件夹");
        String name = zipEntry.getName();
        name = name.substring(0, name.length() - 1);
        File file = new File(outputDirectory + File.separator + name);
        file.mkdir();
} 
else 
{
        File file = new File(outputDirectory + File.separator + zipEntry.getName());
        file.createNewFile();
        outputStream = new FileOutputStream(file);
        System.out.println("你正在解压缩"+file.getName()+"文件");
        PBEKeySpec keySpec = new PBEKeySpec(pwd.toCharArray());
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
    SecretKey passwordKey = keyFactory.generateSecret(keySpec);
    byte[] salt = new byte[8];
    inputStream.read(salt);
    int iterations = 100;
    PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, iterations);
    Cipher cipher = Cipher.getInstance(ALGORITHM);
    cipher.init(Cipher.DECRYPT_MODE, passwordKey, parameterSpec);
    byte[] input = new byte[1024];
    int bytesRead;
    while ((bytesRead = inputStream.read(input)) != -1) 
    {
            byte[] output = cipher.update(input, 0, bytesRead);
            if (output != null)
            {
                    outputStream.write(output);
            }
    }
    byte[] output = cipher.doFinal();
    if (output != null)
    {
            outputStream.write(output);
    }
/*                                    outputStream.flush();
                                    outputStream.close();*/
        
}
                        }
                        //inputStream.close();
                }
                catch(IOException ex)
                {
                        throw new Exception("解压读取文件失败");
                }
                catch(Exception ex)
                {
                        throw new Exception("解压文件密码不正确");
                }
/*                finally
                {
                        inputStream.close();
                        outputStream.flush();
                    outputStream.close();
                }*/
        }

}

3:进一步 实现先前的想法,封装一个OOZip类, 基本思想: 1:抽取常用变量,比如bufferSize 缓冲区大小 buf缓冲区; 本想着加入压缩和解压缩的流变量,后来删掉了 2:定义构造函数, 设置缓冲区大小 3:复制之前的方法,并利用buffersize和buf改写copy函数和 文件的复制的函数 4:进行简单地压缩和解压缩文件夹 加密压缩和解加密压缩文件夹 的测试。 并找到了压缩单个文件的bug 5:bug修复

完整代码如下:

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Random;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

/**
* @author    叶昭良
* @time      2015年2月12日下午9:51:11
* @version   OOZip    用于压缩和解压缩
*                   V1.0  增加了压缩 
*                   V2.0   ZipShared加入了 zosTemp.close(); 修复了 压缩的bug
*                   V3.0   改进了构造函数 利用具有缓冲区的压缩
*                   V4.0   升级了ZipShared 使用了copy函数。
*                   V5.0   增加了加密压缩 和解加密压缩
*                   V6.0   改用了面向对象方式修改了一番
*                   V7.0   加入了一些压缩和解压缩完成的的console标记
*                   V8.0   修复了单个文件无法加密的bug   new ZipEntry(base) 改为
*                    new ZipEntry(base+fileinput.getName()),未添入到zipentry的缘故
*                    而若是文件夹遍历的时候则是有加入文件名的标记!所以在单个文件的时候也需要加入文件名的
*                    标记
*                   V9.0   若有中文问题,可以进一步采用import org.apache.tools.zip.* 的zip包! 更好的支持中文
*                          具体参看http://blog.csdn.net/liu149339750/article/details/7887701  
*                                 http://szhnet.iteye.com/blog/199059 ,这个链接当中提供了ant版本 
*                          当然此版本,不需要org.apache.tool.zip包也不需要ant包  附录了ant版本的代码,的确看起来
*                          是简单的。
*/
public class OOZip
{

/**
*  这几个私有变量的控制,主要体现在针对具体的文件的复制过程中
*/
        private int bufSize ; //压缩和解压缩会用到。 一次从压缩文件zip读取多少文件信息
                                                                 //或者一次写入多少文件信息到压缩流
        private byte[] buf;   //写入或者写出压缩流的字节数组
        private int readBytes = 0;  //实际写入或者写出文件流的大小。
        private static final String ALGORITHM = "PBEWithMD5AndDES";
        
        //构造函数的定义
   public OOZip(){ 
           // 1025*512  //设置输入输出流的缓冲区的大小 ,统一设置
        this(1024*512); 
    } 

    public OOZip(int bufSize){ 
        this.bufSize = bufSize; 
        this.buf = new byte[this.bufSize]; 
    } 
        
        //常用的类中 内部函数
        
        public static void main(String[] args)
        {
                // TODO Auto-generated method stub
                OOZip oz = new OOZip();
                //单个文件加密和非加密测试暂时失败
                oz.ZipShared("e://student.txt", "e://laoliang"); 
                //oz.ZipSharedCrypto("e://student.txt", "e://laoliang","1234");
                //输入文件夹路径则加密和非加密测试通过
                //oz.ZipShared("e://test1222bak", "e://laoliang");  //已测试通过
                //oz.ZipSharedCrypto("e://test1222bak", "e://laoliang", "123456");
                
                //解压缩,不用输入.zip后缀,只需要输入文件名
                //oz.unzipCrypto("e://laoliang", "c://laozi","123456");
                //测试成功
        }

        /**
         *     压缩名字为fileinput变量内容的文件夹
         * @param fileinput   文件夹名字
         * @param zos         zip文件夹名字
         */
        public void ZipShared(String fileinput,String zos)
        {
                try
                {
                        //加入"zip"后缀!
                        ZipOutputStream zosTemp = new ZipOutputStream(new FileOutputStream(zos+".zip"));
                        File fApple = new File(fileinput);
                        ZipShared(fApple,zosTemp,"");
                        try
                        {
                                /// 为什么加入这个就可以????
                                //  不加入这有异常????why   Tell me 
                                zosTemp.close();
                        } catch (IOException e)
                        {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                        }
                } catch (FileNotFoundException e)
                {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                System.out.println("success to create"+zos+".zip");
        }
        /**
         *     压缩文件夹的中间函数
         * @param fileinput    输入函数的文件对象
         * @param zos          压缩输出流对象
         * @param base         一般是"" 表示子目录的作用,在递归目录的时候会用到,在文件夹递归中,涉及到改变;
         */
        public  void ZipShared(File fileinput,ZipOutputStream zos,String base)
        {
if(fileinput.isDirectory())
{
        System.out.println("你正在进入"+fileinput+"文件夹");
        File[] fBanana = fileinput.listFiles();
        try
        {
                //传进一个文件夹标志
                zos.putNextEntry(new ZipEntry(base+"/"));
                //让base加上一个/
                base = base.length()==0?"":base+"/";
                for(int i = 0; i < fBanana.length; i++)
                {
                        ZipShared(fBanana[i],zos,base+fBanana[i].getName());
                }
        } catch (IOException e)
        {
                System.out.println("压缩文件夹失败"+e.getMessage());
        }
        
}else
{
        try
        {
                zos.putNextEntry(new ZipEntry(base+fileinput.getName()));
                FileInputStream fis = new FileInputStream(fileinput);
                //改进写入的方式
                /*int b;
                while((b = fis.read())!= -1)
                {
                        zos.write(b); 
                        //效率很定不高  每一个字符  进行一次缓冲
                        //zos.flush();
                }*/
                copy(fis,zos); //利用汝鹏版的copy函数
                System.out.println("你正在压缩"+fileinput.getName());
        } catch (IOException e)
        {
                System.out.println("压缩文件失败"+e.getMessage());
        } 
}
        }
        /**
         *     加密压缩文件夹
         * @param fileinput    文件夹字符串
         * @param zosFile      压缩字符串名字
         * @param pwd          加密的密码
         */
        public  void ZipSharedCrypto(String fileinput,String zosFile,String pwd)
        {
                
                try
                {        
                        File f1 = new File(fileinput);
                        //采用和ZipShared一样的FileOutputStream
                        ZipOutputStream zos  = null;
                        zos = new ZipOutputStream(new FileOutputStream(zosFile+".zip"));
                        ZipSharedCrypto(f1,zos,"", pwd);
                        try
                        {
                                zos.close();
                        } catch (IOException e)
                        {
                                e.printStackTrace();
                        }
                } catch (FileNotFoundException e)
                {
                        System.out.println("未找到文件"+e.getMessage());
                }
                System.out.println("success to create crypto "+zosFile+".zip");
        }
        /**
         *          加密压缩文件夹     
         * @param fileinput     压缩文件夹的File对象
         * @param zos           zip压缩输出流ZipOutputStream
         * @param base          一般是""
         * @param pwd           压缩的密码
         */
        public  void ZipSharedCrypto(File fileinput,ZipOutputStream zos,String base,String pwd)
        {
if(fileinput.isDirectory())
{
        System.out.println("你正在进入"+fileinput+"文件夹");
        File[] fApples = fileinput.listFiles();
        //因为ZipEntry的isDirectory()方法中,目录以"/"结尾
        try
        {        
                zos.putNextEntry(new ZipEntry(base+"/"));
                base = base.length()==0?"":(base+"/");
                //一种比较新型的方式循环读写东西。
                for(File ftemp:fApples)
                {
                        ZipSharedCrypto(ftemp,zos,base+ftemp.getName(),pwd);
                }
        }catch(IOException e)
        {
                System.out.println("文件夹加密压缩失败");
        }
}else
{        
        
        try
        {
                zos.putNextEntry(new ZipEntry(base));
                FileInputStream fis = new FileInputStream(fileinput);
                System.out.println("你正在开始加密压缩"+fileinput+"文件");
                //加密过程的开始
                PBEKeySpec keySpec = new PBEKeySpec(pwd.toCharArray());
                SecretKeyFactory keyFactory = null;
                try
                {
                        keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
                } catch (NoSuchAlgorithmException e)
                {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                SecretKey passwordKey = keyFactory.generateSecret(keySpec);
                //生成一个炸弹 进行加密
                byte[] bomb =  new byte[8];
                Random rnd = new Random();
                rnd.nextBytes(bomb);
                int iterations = 100;
                PBEParameterSpec parameterSpec = new PBEParameterSpec(bomb, iterations);
                Cipher cipher = null;
                try
                {
                        cipher = Cipher.getInstance(ALGORITHM);
                } catch (NoSuchAlgorithmException
                                | NoSuchPaddingException e)
                {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                cipher.init(Cipher.ENCRYPT_MODE, passwordKey,parameterSpec);
                //往输出流 添加炸弹
                zos.write(bomb);
                
                //添加加密的主文件内容  1KB缓存区
                //byte[] inputBuffer = new byte[1024];
                //int bytesRead = 0;
                //如果没有读到信息则为-1
                
                //改用 readBytes  buf在类头定义的私有变量,进行统一的buffer缓存区大小的控制
                while((this.readBytes = fis.read(this.buf))!= -1)
                {
                        //每个缓冲区 进行加密写入
                        byte[] output = cipher.update(this.buf);
                        if(output != null)
                        {
                                zos.write(output);
                        }
                }
                
                //加密结束语-------------加密结束
                byte[] outputFinal =null;
                try
                {
                        outputFinal = cipher.doFinal();
                } catch (IllegalBlockSizeException | BadPaddingException e)
                {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                if(outputFinal != null)
                {
                        zos.write(outputFinal);
                }        
        }catch(InvalidKeySpecException | InvalidKeyException | InvalidAlgorithmParameterException | IOException e)
        {
                System.out.println("加密失败");
        }
}
        }
        /**
         *   解压缩 zip文件,只能限制为zip ,rar无法进行,利用如鹏版的
         * @param zipName        待解压的zip文件
         * @param outputfolder   解压zip文件到outputFoler文件夹下
         */
        public void unzip(String zipName,String outputfolder)
        {
                File gtkDir = new File(outputfolder);// *.dll放的文件夹
                //指定的目录不存在  则创建之
                if (!gtkDir.exists())
                {
                        gtkDir.mkdirs();
                }
                InputStream inStream = null;
                try
                {
                        //不用输入.zip后缀,只需要输入文件名
                        inStream = new  FileInputStream(zipName+".zip");
                } catch (FileNotFoundException e1)
                {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                }
                //InputStream inStream = Utils.class.getResourceAsStream("/gtkshare.zip");
                if (inStream == null)
                {
                        throw new UnsatisfiedLinkError("没找到"+zipName);
                }
                try
                {                        
                        unzip(inStream, gtkDir.toString());
                        //System.out.println(gtkDir.toString());
                        System.out.println("成功解压缩"+zipName+".zip"+"文件 到"+outputfolder+"文件夹下");
                } catch (IOException e)
                {
                        System.err.println("解压缩"+zipName+".zip失败" + toFullString(e));
                }
        }

        /**
         * 把streamToZip这个zip文件流解压到硬盘的destDir文件夹,支持多级目录
         * @param streamToZip
         * @param destDir
         * @throws IOException
         */
        public  void unzip(InputStream streamToZip,String destDir)throws IOException
        {  
                ZipInputStream zipStream = new ZipInputStream(streamToZip);
try
{
        ZipEntry zipEntry = null;
        //通过zipEntry方式支持多级目录
while((zipEntry=zipStream.getNextEntry())!=null)
{
        if(zipEntry.isDirectory())
        {
                System.out.println("你正在创建文件夹文件 比较特殊");
                File dir = new File(destDir,zipEntry.getName());
                //如果指定的目录不存在 则创建之
                if(!dir.exists())
                {
                        dir.mkdirs();
                }
        }
        else
        {
                FileOutputStream fileOutStream = new FileOutputStream(new File(destDir,zipEntry.getName()));
                try
                {
                        copy(zipStream, fileOutStream);
                }
                finally
                {
                        close(fileOutStream);
                }
                System.out.println("你正在解压缩压缩"+zipEntry.getName());
        }
}
                }
                finally
                {
                        close(zipStream);
                }
                
    }
        /**
         *     从zip文件包中拷贝文件 ,按照0.5MB的缓冲写入文件(默认方式)
         * @param inStream       zipEntry的某个文件
         * @param outStream      输出的某个文件流
         * @throws IOException
         */
        public void copy(InputStream inStream, OutputStream outStream)
                        throws IOException
        {
                //byte[] buffer = new byte[512 * 1024];// 0.5MB 的缓冲区
                //int len;
                while ((this.readBytes = inStream.read(this.buf)) >= 0)
                {
                        outStream.write(this.buf, 0, this.readBytes);
                }
        }
        /**
         *    摘自rupeng.gtk4j   不明白具体的作用    非主要问题
         * @param throwable
         * @return
         */
        public String toFullString(Throwable throwable)
        {
                StringWriter sw = null;
                PrintWriter pw = null;
                try
                {
                        sw = new StringWriter();
                        pw = new PrintWriter(sw);
                        throwable.printStackTrace(pw);
                        return sw.toString();
                } finally
                {
                        close(sw);
                        close(pw);
                }
        }
        /**
         *     让文件流安静的关闭
         * @param closeable   关闭接口
         */
        public void close(Closeable closeable)
        {
                if (closeable != null)
                {
                        try
                        {
                                closeable.close();
                        } catch (IOException e)
                        {

                        }
                }
        }
        
        // 加密解压缩

/**
         * 功能描述:将压缩文件解压到指定的文件目录下
         * @param zipFileName      压缩文件名称(带路径)
         * @param outputDirectory  指定解压目录
         * @return
         * @throws Exception
         */
        public  void unzipCrypto(String zipFileName, String outputDirectory, String pwd)
        {
                ZipInputStream inputStream;
                File outputDir;
                try
                {
                        //不用输入.zip后缀,只需要输入文件名
                        inputStream = new ZipInputStream(new FileInputStream(zipFileName+".zip"));
                        outputDir = new File(outputDirectory);
                        unzipCrypto(inputStream, outputDir, pwd);
                } catch (Exception e)
                {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                System.out.println("成功解压缩"+zipFileName+".zip"+"文件 到"+outputDirectory+"文件夹下");
                
        }


        public void unzipCrypto(ZipInputStream inputStream, File outputDir, String pwd) throws Exception
        {
                ZipEntry zipEntry = null;
                FileOutputStream outputStream = null;
                try{
while ((zipEntry = inputStream.getNextEntry()) != null) 
{
        //如果是文件夹  则遍历
        if (zipEntry.isDirectory())
        {
                System.out.println("你正在进入"+zipEntry.getName()+"文件夹");
                String name = zipEntry.getName();
                name = name.substring(0, name.length() - 1);
                File file = new File(outputDir + File.separator + name);
                file.mkdir();
        } 
        //对单个普通文件进行处理
        else 
        {
                File file = new File(outputDir + File.separator + zipEntry.getName());
                file.createNewFile();
                outputStream = new FileOutputStream(file);
                System.out.println("你正在解压缩"+file.getName()+"文件");
                //解压加密过程的开始
                PBEKeySpec keySpec = new PBEKeySpec(pwd.toCharArray());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
            SecretKey passwordKey = keyFactory.generateSecret(keySpec);
            //准备排除加密的炸弹头
            byte[] apple = new byte[8];
            //在zip输入流添加read
            inputStream.read(apple);
            int iterations = 100;
            PBEParameterSpec parameterSpec = new PBEParameterSpec(apple, iterations);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, passwordKey, parameterSpec);
            //byte[] input = new byte[1024];
            //int bytesRead;
            //利用全局的私有变量this.buf  this.readBytes ,已在类开头定义,统一控制
            while ((this.readBytes = inputStream.read(this.buf)) != -1) 
            {
                    byte[] output = cipher.update(this.buf, 0, this.readBytes);
                    if (output != null)
                    {
                            outputStream.write(output);
                    }
            }
            byte[] output = cipher.doFinal();
            if (output != null)
            {
                    outputStream.write(output);
            }
                
        }
}
                }
                catch(IOException ex)
                {
                        throw new Exception("解压读取文件失败");
                }
                catch(Exception ex)
                {
                        throw new Exception("解压文件密码不正确");
                }
        }

}
/*
*  附录ant版本的压缩实现http://szhnet.iteye.com/blog/199059
*  可以加入某些文件和删除某些文件
*  package net.szh.zip;

import java.io.File;

import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Zip;
import org.apache.tools.ant.types.FileSet;

public class ZipCompressorByAnt {

        private File zipFile;

        public ZipCompressorByAnt(String pathName) {
                zipFile = new File(pathName);
        }
        
        public void compress(String srcPathName) {
                File srcdir = new File(srcPathName);
                if (!srcdir.exists())
                        throw new RuntimeException(srcPathName + "不存在!");
                
                Project prj = new Project();
                Zip zip = new Zip();
                zip.setProject(prj);
                zip.setDestFile(zipFile);
                FileSet fileSet = new FileSet();
                fileSet.setProject(prj);
                fileSet.setDir(srcdir);
                //fileSet.setIncludes("**//*.java"); 包括哪些文件或文件夹 eg:zip.setIncludes("*.java");
                //fileSet.setExcludes(...); 排除哪些文件或文件夹
                zip.addFileset(fileSet);
                
                zip.execute();
        }
}

ant版本的使用:
package net.szh.zip;

public class TestZip {
        public static void main(String[] args) {                
                ZipCompressorByAnt zca = new ZipCompressorByAnt("E:\\szhzipant.zip");
                zca.compress("E:\\test");
        }
}
*  
*/
Related
叶昭良
叶昭良
Engineer of offshore wind turbine technique research

My research interests include distributed energy, wind turbine power generation technique , Computational fluid dynamic and programmable matter.