How to extract specific file in a zip file in java
Asked Answered
I

6

15

I need to provide a view of zip file to customer in system, and allow customers download choosed files.

  1. parse the zip file and show on the web page. and remember every zipentry location(for example file1 is starting from byte 100 width length 1024bytes) in backend.
  2. download the specified file when customer click the download button.

now I have rememberred all zipentry locations, but is there java zip tools to unzip the specified location of zip files?? API just like unzip(file, long entryStart, long entryLength);

Idoux answered 24/8, 2015 at 9:42 Comment(2)
Read this : mkyong.com/java/how-to-decompress-files-from-a-zip-fileBeauregard
Thanks, but this is not what i wantIdoux
W
24

This can be done without messing with byte arrays or input streams using Java 7's NIO2:

public void extractFile(Path zipFile, String fileName, Path outputFile) throws IOException {
    // Wrap the file system in a try-with-resources statement
    // to auto-close it when finished and prevent a memory leak
    try (FileSystem fileSystem = FileSystems.newFileSystem(zipFile, null)) {
        Path fileToExtract = fileSystem.getPath(fileName);
        Files.copy(fileToExtract, outputFile);
    }
}
Wichman answered 24/6, 2016 at 21:18 Comment(0)
N
13

You can use the below code to extract a particular file from zip:-

public static void main(String[] args) throws Exception{
        String fileToBeExtracted="fileName";
        String zipPackage="zip_name_with_full_path";
        OutputStream out = new FileOutputStream(fileToBeExtracted);
        FileInputStream fileInputStream = new FileInputStream(zipPackage);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream );
        ZipInputStream zin = new ZipInputStream(bufferedInputStream);
        ZipEntry ze = null;
        while ((ze = zin.getNextEntry()) != null) {
            if (ze.getName().equals(fileToBeExtracted)) {
                byte[] buffer = new byte[9000];
                int len;
                while ((len = zin.read(buffer)) != -1) {
                    out.write(buffer, 0, len);
                }
                out.close();
                break;
            }
        }
        zin.close();

    }

Also refer this link: How to extract a single file from a remote archive file?

Necessitous answered 24/8, 2015 at 9:53 Comment(1)
It works well just for one situation, that is, there is compressSize and raw entry size saved in each entry header. But some of zip files have not these info saved in entry header, in this case, zin.getNextEntry() will read though over the previous entries data to reach the next entry instead of seeking to the next entry, So it will perform slow.Idoux
N
8

You can try like this:

ZipFile zf = new ZipFile(file);
try {
  InputStream in = zf.getInputStream(zf.getEntry("file.txt"));
  // ... read from 'in' as normal
} finally {
  zf.close();
}

I havent tried it but in Java 7 ZipFileSystem you can try like this to extract file.TXT file from the zip file.

Path zipfile = Paths.get("/samples/ziptest.zip");
FileSystem fs = FileSystems.newFileSystem(zipfile, env, null);
final Path root = fs.getPath("/file.TXT");
Neotropical answered 24/8, 2015 at 10:24 Comment(0)
H
0

To use FileSystems.newFileSystem you need the first parameter to be made with URI.create

You need to specify the correct protocol. "jar:file:"

Also: you need a Map<String,String>() with properties:

map.put("create","true"); (or "false" to extract)
extract("/tmp","photos.zip","tiger.png",map)

void extract(String path, String zip, String entry, Map<String,String> map){
        try (FileSystem fileSystem = FileSystems.newFileSystem(URI.create("jar:file:"+ path + "/" + zip), map)) {
           Path fileToExtract = fileSystem.getPath(entry);
           Path fileOutZip = Paths.get(path + "/unzipped_" + entry );
           Files.copy(fileToExtract, fileOutZip);

}
}
Halftimbered answered 12/2, 2021 at 17:1 Comment(0)
P
0

So I had a problem related but not quite answered here. How do I extract only multiple specific files if I only have a ZipInputStream as I'm streaming a download. This drove me nuts as it's not obvious how to get the next entry int the input stream if you don't want to unpack them all. The answer is tail recursion.

  static void caller() {
      // res.body() is from java's http client, but basically wherever you get the inputstream that is a zip
      var dir = Files.createTempDirectory();
      try (var is = new ZipInputStream(res.body())) {
        recurseExtract(is, is.getNextEntry(), dir);
      }
  }

  static void recurseExtract(ZipInputStream is, ZipEntry entry, Path dir) throws IOException {
    if (entry == null) {
      return;
    }
    if (shouldExtract(entry.getName())) {
      var path = Path.of(entry.getName());
      if (path.getNameCount() > 1) {
        if (entry.isDirectory() ) {
          Files.createDirectory(dir.resolve(path));
        }
        else {
          System.out.println("Extracting " + dir.resolve(noRoot));
          Files.copy(is, dir.resolve(noRoot));
        }
      }
    }
    is.closeEntry(); // not certain this is necessary
    recurseExtract(is, is.getNextEntry(), dir);
  }

  static boolean shouldExtract(String entry) {
    // check for ".." to avoid zip slip security vulnerability
    return ! entry.contains(".."); // put other filtering here, but check for the .. too somewhere
  }

I'm not certain if this is the most efficient way to stream and unpack a zip file. I'll speculate it's better than downloading and saving the file fully and then re-reading the whole thing.

Panga answered 25/2 at 20:21 Comment(0)
A
-1

I worked with a case where:
step 1: I have zip file in specified directory to unzip
step 2: Store the unzipped files (more than one file in a zip file) in a specified directory) (NOTE: clean the destination directory where you want to move the unzipped files).

Here is the code that worked for me:

public String unZip(String zipFilePath, String destDirectory, String afilename) {
        
        String efilename; String[] files; String unzipfilePath; String[] oldFiles;
        File destDir = new File(destDirectory);
        if (destDir.isDirectory()) {
            oldFiles = destDir.list();
               for (int k = 0; k < oldFiles.length; k++) {
                   File oFiles = new File(oldFiles[k]);
                   logMessage("Old file name in the unziped folder is "+oFiles );
                   oFiles.delete();
                }
                
            }
        if (!destDir.exists()) {
            destDir.mkdir();
        }
        
         ZipInputStream zipIn;
        try {
            zipIn = new ZipInputStream(new FileInputStream(zipFilePath));

            ZipEntry entry = zipIn.getNextEntry();
            // iterates over entries in the zip file
            while (entry != null) {
                
                unzipfilePath = destDirectory + File.separator + entry.getName();
                 
                if (!entry.isDirectory()) {
                    // if the entry is a file, extracts it
                    extractFile(zipIn, unzipfilePath);
                     logMessage(" File copied to Unziped folder is " +unzipfilePath);
                } else {
                    // if the entry is a directory, make the directory
                    File dir = new File(unzipfilePath);
                    dir.mkdir();
                }
                zipIn.closeEntry();
                entry = zipIn.getNextEntry();
            }
            zipIn.close(); 
            
            // check for filename in the unzipped folder
            
            File dest = new File(destDirectory);
            files = dest.list();
            int flag = 0;
            if (files == null) {
                logMessage("Empty directory.");
            }
            else {
      
                // Linear search in the array forf expected file name 
                for (int i = 0; i < files.length; i++) {
                    efilename = files[i];
                    if (efilename.equals(afilename))
                        logMessage(efilename + " Expected File found in Unziped files folder");
                        flag = 1;
                        Assert.assertNotNull(efilename);
                       
                }
                    
            }
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        return efilename;
    }
Alsatian answered 16/9, 2021 at 1:16 Comment(1)
downvoted because so much uncompilable code. I feel like extractFile is kind of important herePanga

© 2022 - 2024 — McMap. All rights reserved.