简体   繁体   中英

Java, creating two identical zip files if content are the same

I have this, which works fine for zipping and unzipping:

    public static final String SLASH = "/";
    public static void zip(int level, File zipfile, File... files) throws IOException {
            try (FileOutputStream fo = new FileOutputStream(zipfile); ZipOutputStream zo = new ZipOutputStream(fo)) {
                    zo.setLevel(level);

                    for (File file : files) {
                            zip("", file, zo);
                    }

                    zo.flush();
                    zo.finish();
                    zo.close();

                    // !!!!!!!! Tried these !!!!!!!!!
                    long time = Cal.date(1970, Cal.Month.JANUARY, 1).getTime();
                    zipfile.setLastModified(time);
                    Files.setAttribute(zipfile.toPath(), "lastAccessTime", FileTime.fromMillis(time) );
            }
    }

    public static File unzip(File zipfile, File to) throws IOException {
            ZipFile                         filezipped = new ZipFile( zipfile );
            Enumeration<? extends ZipEntry> entries    = filezipped.entries( ) ;

            while ( entries.hasMoreElements() ) {

                    ZipEntry zipEntry = entries.nextElement( )             ;
                    File     file     = new File( to, zipEntry.getName( ) );

                    if ( zipEntry.isDirectory() ) {
                            file.mkdirs();
                    }
                    else {
                            file.getParentFile().mkdirs();
                            try ( InputStream in = filezipped.getInputStream(zipEntry) ) {
                                    Files.copy( in, file.toPath() );
                            }
                    }
            }

            return zipfile;
    }

    private static void zip(String base, File file, ZipOutputStream zo) throws IOException {
            String path   = base + file.getName();
            if ( file.isDirectory() ) {
                    path += SLASH;

                    zo.putNextEntry( new ZipEntry(path) );

                    for (File ff : file.listFiles()) {
                            zip(path, ff, zo);
                    }

                    zo.closeEntry();

            } else {
                    zo.putNextEntry( new ZipEntry(path) );

                    Files.copy(file.toPath(), zo);

                    zo.closeEntry();
            }
    }

However, the zip file will have a different checksum even though the content of the file is unchanged. This is a problem when committing the files using git.

How can I ensure that the zipped file stays the same every time unless content has changed?

The timestamp on the ZIP file itself shouldn't matter, but try setting the last modification time of the ZIP entries to a constant value:

ZipEntry entry = new ZipEntry(path);
entry.setTime(0);

zo.putNextEntry(entry);

See the setTime JavaDoc for more info.


Update

The above should indeed do the trick, provided the content and order of your entries is identical. I took a look at the source code for ZipOutputStream , and found the following in the putNextEntry method:

if (e.time == -1) {
    e.setTime(System.currentTimeMillis());
}

So setting the time to 0 before adding the entry to the stream should prevent it from being overwritten, and keep your content constant.

I'm not certain what your Cal class is doing, but I suspect that internally it's creating a Calendar instance and setting the date fields. You should be aware that if you do this then it will still end up with the current time of day, not 00:00! So you are most likely not getting the same timestamp each time.

I'd just try

long time = 0;

rather than mucking about with calendar instances.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM