网络书屋(Web Reading Room)

A blogging framework for hackers.

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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类来实现

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
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修复

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
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");
        }
}
*  
*/