用Java创建zip存档

Creating zip archive in Java

我有一个7zip程序创建的文件。 我用deflate方法压缩它。 现在,我要在java中创建相同的归档文件(具有相同的MD5sum)。 当我创建zip文件时,我使用了在Internet上找到的算法,例如http://www.kodejava.org/examples/119.html,但是当我使用此方法创建zip文件时,压缩后的大小大于的大小。 未压缩的文件,这是怎么回事? 这不是一个非常有用的压缩。 那么,如何创建与7zip程序创建的zip文件完全相同的zip文件? 如果有帮助,我可以获得在7zip程序中创建的有关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
// simplified code for zip creation in java

import java.io.*;
import java.util.zip.*;

public class ZipCreateExample {

    public static void main(String[] args) throws Exception {

        // input file
        FileInputStream in = new FileInputStream("F:/sometxt.txt");

        // out put file
        ZipOutputStream out = new ZipOutputStream(new FileOutputStream("F:/tmp.zip"));

        // name the file inside the zip  file
        out.putNextEntry(new ZipEntry("zippedjava.txt"));

        // buffer size
        byte[] b = new byte[1024];
        int count;

        while ((count = in.read(b)) > 0) {
            out.write(b, 0, count);
        }
        out.close();
        in.close();
    }
}


只是为了澄清一下,您为原始文件使用了7zip中的ZIP算法? 7zip也声称比其他供应商高2-10%的压缩率。我敢猜测,Java内置的ZIP算法的优化程度不及7zip中的那种。如果需要类似的压缩文件,最好的办法是从命令行调用7zip。

您是否要解压缩ZIP文件,更改其中的文件,然后重新压缩它以使其具有相同的MD5哈希值?散列旨在防止您这样做。


ZipOutputStream有几种调整压缩的方法:

公共无效setMethod(int方法)

Sets the default compression method
for subsequent entries. This default
will be used whenever the compression
method is not specified for an
individual ZIP file entry, and is
initially set to DEFLATED.

公共无效setLevel(int级别)

Sets the compression level for
subsequent entries which are DEFLATED.
The default setting is DEFAULT_COMPRESSION. level - the compression level (0-9)

当您添加类似以下内容时:

1
2
3
4
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(target));
zos.setMethod( ZipOutputStream.DEFLATED );
zos.setLevel( 5 );
...

它不会改善您的压缩率吗?


这是一个传递绝对路径的函数,它将创建一个与目录名称相同的zip文件(在该目录下,您希望对所有子文件夹和文件进行zip,所有内容都是!!),如果成功则返回true,否则返回false如果有的话。

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
public class FileUtil {
final static int BUFFER = 2048;
private static Logger log = Logger.getLogger(FileUtil.class);

      public static boolean createZipArchive(String srcFolder) {

    try {
        BufferedInputStream origin = null;



        FileOutputStream    dest = new FileOutputStream(new File(srcFolder+".zip"));

        ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
        byte data[] = new byte[BUFFER];

        File subDir = new File(srcFolder);
        String subdirList[] = subDir.list();
        for(String sd:subdirList)
        {
                // get a list of files from current directory
                File f = new File(srcFolder+"/"+sd);
                if(f.isDirectory())
                {
                    String files[] = f.list();

                    for (int i = 0; i < files.length; i++) {
                        System.out.println("Adding:" + files[i]);
                        FileInputStream fi = new FileInputStream(srcFolder  +"/"+sd+"/" + files[i]);
                        origin = new BufferedInputStream(fi, BUFFER);
                        ZipEntry entry = new ZipEntry(sd +"/"+files[i]);
                        out.putNextEntry(entry);
                        int count;
                        while ((count = origin.read(data, 0, BUFFER)) != -1) {
                            out.write(data, 0, count);
                            out.flush();
                        }

                    }
                }
                else //it is just a file
                {
                    FileInputStream fi = new FileInputStream(f);
                    origin = new BufferedInputStream(fi, BUFFER);
                    ZipEntry entry = new ZipEntry(sd);
                    out.putNextEntry(entry);
                    int count;
                    while ((count = origin.read(data, 0, BUFFER)) != -1) {
                        out.write(data, 0, count);
                        out.flush();
                    }

                }
        }
        origin.close();
        out.flush();
        out.close();
    } catch (Exception e) {
        log.info("createZipArchive threw exception:" + e.getMessage());        
        return false;

    }


    return true;
}  
  }

要从同一源文件生成两个相同的zip文件(包括相同的md5sum),我建议使用相同的zip实用程序-始终使用相同的Java程序,或者始终使用7zip。

例如7zip实用程序有很多选项-其中许多只是可以自定义的默认值(或版本之间有所不同?),并且任何Java zip实现都必须明确设置这些选项。如果您的Java应用程序可以简单地调用外部" 7z"程序,则无论如何,您都可能会获得比自定义Java zip实现更好的性能。 (这也是map-reduce问题的一个很好的例子,您可以在其中轻松扩展实现。)

但是,如果您拥有服务器端生成的zip文件和客户端端生成的zip文件,则将遇到的主要问题是,该zip文件除了存储原始文件外还存储两件事:(1)文件名,以及(2)文件时间戳。如果其中任何一个已更改,那么生成的zip文件将具有不同的md5sum:

1
2
3
4
5
6
7
8
9
10
$ ls tst1/
foo.tar

$ cp -r tst1 tst2

$ ( cd tst1; zip foo.zip foo.tar )  ; ( cd tst2; zip foo.zip foo.tar )   ; md5sum tst?/foo.zip
updating: foo.tar (deflated 20%)
updating: foo.tar (deflated 20%)
359b82678a2e17c1ddbc795ceeae7b60  tst1/foo.zip
b55c33c0414ff987597d3ef9ad8d1d08  tst2/foo.zip

但是,使用" cp -p"(保留时间戳):

1
2
3
4
5
6
7
$ cp -p -r tst1 tst2

$ ( cd tst1; zip foo.zip foo.tar )  ; ( cd tst2; zip foo.zip foo.tar )   ; md5sum tst?/foo.zip
updating: foo.tar (deflated 20%)
updating: foo.tar (deflated 20%)
359b82678a2e17c1ddbc795ceeae7b60  tst1/foo.zip
359b82678a2e17c1ddbc795ceeae7b60  tst2/foo.zip

即使文件名和路径相同,您也会发现文件名和路径不同的问题。


请在下面的代码中找到具有zip和unzip功能的代码。希望它可以帮助某人。

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
package com.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;


/**
 * @author dinesh.lomte
 *
 */

public class ZipUtil {

    /**
     *
     * @param source
     * @param destination
     */

    public static void unZip(String source, String destination) {

        String method ="unZip(String source, String destination)";
        ZipInputStream zipInputStream = null;
        try {
            // Creating the ZipInputStream instance from the source file
            zipInputStream = new ZipInputStream(new FileInputStream(source));
            // Getting the zipped file list entry
            ZipEntry zipEntry = zipInputStream.getNextEntry();
            // Iterating through the file list entry
            while (zipEntry != null) {
                String fileName = zipEntry.getName();
                File file = new File(new StringBuilder(destination)
                    .append(File.separator)
                    .append(AppUtil.getFileNameWithoutExtension(
                            AppUtil.getNameFromPath(source)))
                    .append(File.separator).append(fileName).toString());                
                // Creating non existing folders to avoid any FileNotFoundException
                // for compressed folder
                new File(file.getParent()).mkdirs();
                FileOutputStream fileOutputStream = new FileOutputStream(file);
                byte[] buffer = new byte[1024];
                int length;
                while ((length = zipInputStream.read(buffer)) > 0) {
                    fileOutputStream.write(buffer, 0, length);
                }
                fileOutputStream.close();
                zipEntry = zipInputStream.getNextEntry();
            }
        } catch (IOException iOException) {
            System.out.println("Failed to unzip the ''{0}'' file located in ''{1}'' folder. Due to, {2}");

        } finally {
            // Validating if zipInputStream instance in not null
            if (zipInputStream != null) {
                try {
                    zipInputStream.closeEntry();
                    zipInputStream.close();
                } catch (IOException iOException) {                
                }
            }
        }
    }

    /**
     * Traverse a directory from the source folder location and get all files,
     * and add the file into files list.
     *
     * @param node
     */

    public static void generateFileList(
            String source, File node, List<String> files) {    
        // Validating if the node is a file
        if (node.isFile()) {
            files.add(generateZipEntry(
                    source, node.getPath().toString()));
        }
        // Validating if the node is a directory
        if (node.isDirectory()) {
            String[] subNote = node.list();
            for (String filename : subNote) {
                generateFileList(source, new File(node, filename), files);
            }
        }
    }

    /**
     * Format the file path to zip
     * @param source
     * @param file
     * @return
     */

    private static String generateZipEntry(String source, String file) {
        return file.substring(source.length(), file.length());
    }

    /**
     *
     * @param source
     * @param destination
     */

    public static void zip(String source, String destination) {

        String method ="zip(String source, String destination)";
        ZipOutputStream zipOutputStream = null;        
        try {            
            // Creating the zipOutputStream instance
            zipOutputStream = new ZipOutputStream(
                    new FileOutputStream(destination));
            List<String> files = new ArrayList<>();
            generateFileList(source, new File(source), files);
            // Iterating the list of file(s) to zip/compress
            for (String file : files) {
                // Adding the file(s) to the zip
                ZipEntry zipEntry = new ZipEntry(file);
                zipOutputStream.putNextEntry(zipEntry);
                FileInputStream fileInputStream = new FileInputStream(
                        new StringBuilder(source).append(File.separator)
                        .append(file).toString());
                int length;
                byte[] buffer = new byte[1024];
                while ((length = fileInputStream.read(buffer)) > 0) {
                    zipOutputStream.write(buffer, 0, length);
                }                
                // Closing the fileInputStream instance
                fileInputStream.close();
                // De-allocating the memory by assigning the null value
                fileInputStream = null;
            }
        } catch (IOException iOException) {
            System.out.println("Failed to zip the file(s) located in ''{0}'' folder. Due to, {1}");
        } finally {
            // Validating if zipOutputStream instance in not null
            if (zipOutputStream != null) {
                try {
                    zipOutputStream.closeEntry();
                    zipOutputStream.close();
                } catch (IOException iOException) {
                }
            }
        }
    }
}

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
package comm;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;*emphasized text*
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class Zip1 {
      public static void main( String[] args )
        {
            byte[] buffer = new byte[1024];

            try{

                File f= new  File("E:\\\");
                f.mkdirs();
                File origFile= new File(f,"
MyZipFile2.zip");
                FileOutputStream fos = new FileOutputStream(origFile);

                ZipOutputStream zos = new ZipOutputStream(fos);
                ZipEntry ze= new ZipEntry("
test.pdf");
                zos.putNextEntry(ze);
                FileInputStream in = new FileInputStream("
D:\\\\Test.pdf");

                int len;
                while ((len = in.read(buffer)) > 0) {
                    zos.write(buffer, 0, len);
                }

                in.close();
                zos.closeEntry();

                //remember close it
                zos.close();

                System.out.println("
Done");

            }catch(IOException ex){
               ex.printStackTrace();
            }
        }
}