1

I want to decompress a large folder in ZIP format with nested subdirectories in a directory that already exists. The files inside the ZIP folder can exist in the decompressed directory. I need to keep the previous files only when the date of that file is newer than the date of the file in the ZIP folder. If the file in the ZIP is newer, then I want to overwrite it.

There is some good strategy for doing this? I already checked truezip and zip4j, but I can't find the option (the best option for me so far is modifying the zip4j sources, but it should be a better way.

P.S. If I haven't explained this correctly, please feel free to ask. English is not my native language and I could have expressed anything wrong..

Thanks.

  • Why not use `java.util.zip`? You are in total control of what files you extract, where, and what to do with existing files. – Joni Dec 05 '13 at 11:03
  • 1
    It's a 2 Gb folder, with different names of the files, different encoding of the names... I can implement the java.util.zip, but I feel like is a bit reinventing the wheel, and I can to introduce bugs that have been solved in any other jar already, and probably reducing the performance that I could get with a tested and maintained jar. – user3066166 Dec 05 '13 at 11:38

1 Answers1

3

With Zip4j, this is how it can be done:

import java.io.File;
import java.util.Date;
import java.util.List;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.util.Zip4jUtil;


public class ExtractWithoutOverwriting {

    public static void main(String[] args) {

        try {
            String outputPath = "yourOutputPath";
            ZipFile zipFile = new ZipFile(new File("yourZipFile.zip"));
            if (zipFile.isEncrypted()) {
                zipFile.setPassword("yourPassword".toCharArray());
            }

            @SuppressWarnings("unchecked")
            List<FileHeader> fileHeaders = zipFile.getFileHeaders();

            for (FileHeader fileHeader : fileHeaders) {
                if (fileHeader.isDirectory()) {
                    File file = new File(outputPath + System.getProperty("file.separator") + fileHeader.getFileName());
                    file.mkdirs();
                } else {
                    if (canWrite(outputPath, fileHeader)) {
                        System.out.println("Writing file: " + fileHeader.getFileName());
                        zipFile.extractFile(fileHeader, outputPath);
                    } else {
                        System.out.println("Not writing file: " + fileHeader.getFileName());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static boolean canWrite(String outputPath, FileHeader fileHeader) {
        File file = new File(outputPath + System.getProperty("file.separator") + fileHeader.getFileName());
        //time stamps are stored in dos format in a zip file
        //convert it to java format
        long lastModifiedFromZip = Zip4jUtil.dosToJavaTme(fileHeader.getLastModFileTime());

        //If the file exists, it can be overwritten only if the file in the destination path
        //is newer than the one in the zip file
        return !(file.exists() && isLastModifiedDateFromFileNewer(file.lastModified(), lastModifiedFromZip));
    }

    public static boolean isLastModifiedDateFromFileNewer(long lastModifiedFromFile, long lastModifiedFromZip) {
        Date lastModifiedDateFromFile = new Date(lastModifiedFromFile);
        Date lastModifiedDateFromZip = new Date(lastModifiedFromZip);

        return lastModifiedDateFromFile.after(lastModifiedDateFromZip);
    }

}

What we do here is:

  1. Create a new instance of the ZipFile
  2. If the zip file is encrypted, set a password
  3. Loop over all files in the zip file
  4. Check if a file with this name exists in the output path and if this file's last modification time is "newer" than the one in the zip file. This check is done in the method: canWrite()

This code is not completely tested, but I hope it gives you an idea of a solution.

  • useful even in 2019 :) – Kartik Apr 02 '19 at 11:46
  • Thanks for the answer, I have tested the code and I got both `lastModifiedFromFile` & `lastModifiedFromZip` time is same.. so `lastModifiedDateFromFile.after(lastModifiedDateFromZip)` this condition was always return `false` and file overwrite everytime. – Nikunj Paradva Aug 18 '22 at 11:44
  • to solve this issue i change return method `lastModifiedDateFromFile.after(lastModifiedDateFromZip) || (lastModifiedDateFromFile == lastModifiedDateFromZip)` , Please tell me, is that correct or not? – Nikunj Paradva Aug 18 '22 at 11:45