Using Java I have to read text files which are inside gz file which is in another .tar.gz
gz_ltm_logs.tar.gz is the filename. It then has files ltm.1.gz, ltm.2.gz inside it and then these files have text files in them.
I wanted to do it using java.util.zip.* only but if it is impossible then I can look at other libraries.
I thought I will be able to do it using java.util.zip. But doesn't seem straightforward
Here's some code to give you an idea. This method will try to extract a given tar.gz file to outputFolder.
public static void extract(File input, File outputFolder) throws IOException {
byte[] buffer = new byte[1024];
GZIPInputStream gzipFile = new GZIPInputStream(new FileInputStream(input));
ByteOutputStream tarStream = new ByteOutputStream();
int gzipLengthRead;
while ((gzipLengthRead = gzipFile.read(buffer)) > 0){
tarStream.write(buffer, 0, gzipLengthRead);
}
gzipFile.close();
org.apache.tools.tar.TarInputStream tarFile = null;
// files inside the tar
OutputStream out = null;
try {
tarFile = new org.apache.tools.tar.TarInputStream(tarStream.newInputStream());
tarStream.close();
TarEntry entry = null;
while ((entry = tarFile.getNextEntry()) != null) {
String outFilename = entry.getName();
if (entry.isDirectory()) {
File directory = new File(outputFolder, outFilename);
directory.mkdirs();
} else {
File outputFile = new File(outputFolder, outFilename);
File outputDirectory = outputFile.getParentFile();
if (!outputDirectory.exists()) {
outputDirectory.mkdirs();
}
out = new FileOutputStream(outputFile);
// Transfer bytes from the tarFile to the output file
int innerLen;
while ((innerLen = tarFile.read(buffer)) > 0) {
out.write(buffer, 0, innerLen);
}
out.close();
}
}
} finally {
if (tarFile != null) {
tarFile.close();
}
if (out != null) {
out.close();
}
}
}
I kind of stuck in this problem. I want to print only the top level directory from a zip file. For example I have a zip file with following structure:
Sample.zip
- sound
- game
-start.wav
-end.wav
- Intro
- custom
- Scene
- fight
- Angle
..............
Above figure shows: the Sample.zip has 2 folders (sound and custom), and inside sound there are 2 folders game and Intro and so on...
Now I know how to open and grab the directory from zip file: For example (working code)
try {
appFile = ("../../Sample.zip"); // just the path to zip file
ZipFile zipFile = new ZipFile(appFile);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(entry.isDirectory()){
String dir = entry.getName();
File file = new File(dir);
System.out.println(file.getParent());
}
}
} catch (IOException e) {
System.out.println("Error opening Zip" +e);
}
Now I also know I can use .getParent()(as you see above) to get the top level dir, but the above implementation has not worked. It'll list out all the directory , like
null
sound
game
null
custom
scene
Angle
My question is how can I actually print only the top level folders, In above scenario , sound and custom ?
For any sort of hint, I'll be thankful.
Actually I did following as suggested by #JB Nizet and get a work around(it actually work ):
try {
appFile = ("../../Sample.zip"); // just the path to zip file
ZipFile zipFile = new ZipFile(appFile);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(entry.isDirectory()){
File file = new File(entry.getName());
if(file.getParent() == null){
System.out.println(file.getName());
}
}
}
} catch (IOException e) {
System.out.println("Error opening Zip" +e);
}
The above solution has worked because the top level dir has no parent and therefore returned null as output. So I just loop around the directories to see if they have parents, if they dont have any parent then they are top level directory.
You can use something like that:
try{
String appFile = "../file.zip"; // just the path to zip file
ZipFile zipFile = new ZipFile(appFile);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(entry.isDirectory() && !entry.getName().matches("\\S+/\\S+")){ //it's a top level folder
System.out.println(entry.getName());
}
}
} catch (IOException e) {
System.out.println("Error opening Zip" +e);
}
Maybe this code will help you with using InputStream
String topFolder="";
String topFolder2="";
Boolean hasTopFolder=true;
try{
File dir = new File(path+"/html5"+catalogue.getIdProduit());
if (!dir.exists()) {
dir.mkdirs();
}
String outputFolder= "path/to/outputFolder";
InputStream input = file.getInputstream();
//get the zip file content
ZipInputStream zis = new ZipInputStream(input);
//get the zipped file list entry
ZipEntry ze = zis.getNextEntry();
while(ze!=null){
if (ze.isDirectory()) {
System.out.println("is directory : "+ ze.getName());
if ("".equals(topFolder)){
topFolder = ze.getName().split("/")[0];
System.out.println("is directory topFolder : "+ ze.getName());
}
if (("".equals(topFolder2)) && (!topFolder.equals(ze.getName().split("/")[0]))){
hasTopFolder=false;
topFolder2=ze.getName().split("/")[0];
System.out.println("is directory topFolder2 : "+ ze.getName());
}
ze = zis.getNextEntry();
continue;
}
String fileName = ze.getName();
File newFile = new File(outputFolder + File.separator + fileName);
System.out.println("file unzip : "+ newFile.getAbsoluteFile());
//create all non exists folders
//else you will hit FileNotFoundException for compressed folder
new File(newFile.getParent()).mkdirs();
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
ze = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
System.out.println("Done");
}
catch(IOException e){
e.printStackTrace();
}
if (hasTopFolder){
topFolder="/"+topFolder;
}
else
topFolder="";
What about following method:
/**
* Get the root folders within a zip file
*
* #param zipFile the zip file to be used. E.g. '/home/foo/bar.zip'
* #return a list containing all root folders
* #throws Exception if case the zip file cannot be found or read.
*/
public static List<String> getGetRootDirectoriesWithinZip(String zipFile) throws Exception {
Set<String> set = new LinkedHashSet();
//get the zip file content stream
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipFile));
//get the zipped file set entry
ZipEntry zipEntry = zipInputStream.getNextEntry();
while (zipEntry != null) {
String fileName = zipEntry.getName();
Path path = Paths.get(fileName);
int nameCount = path.getNameCount();
for (int i = 0; i < nameCount; i++) {
if (path != null && path.getParent() != null) {
path = path.getParent();
}
}
set.add(path.toString());
zipEntry = zipInputStream.getNextEntry();
}
List<String> retList = new ArrayList<>();
retList.addAll(set);
return retList;
}
This is the method that worked for me.
I should note that I am using StringUtils (Apache Lang3) to count how many times
"\" appears in the ZipEntry path, although if you don't want to use StringUtils you could make
your own method for counting.
public static ArrayList<ZipEntry> getZipContent(File file, int index) {
try {
ArrayList<String> innerFoldersPaths = new ArrayList<String>();
ArrayList<ZipEntry> retEntries = new ArrayList<ZipEntry>();
ZipFile zipFile = new ZipFile(file);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
// If you also want to get files remove the "if (entry.isDirectory())" statement.
if (entry.isDirectory()) {
String backSlashName = entry.getName().replace("/", "\\"); // Important to do this.
if (StringUtils.countMatches(backSlashName, "\\") > index - 1) { // Using Apache StringUtils
String folder[] = backSlashName.split(Pattern.quote("\\"));
String finalFolder = "";
// Getting the folders path inside the .zip file .
for (int i = 0; i < index; i++) {
folder[i] = folder[i] + "\\";
finalFolder = finalFolder + folder[i];
}
finalFolder = finalFolder.replace("\\", "/"); // Important to do this.
if (innerFoldersPaths.contains(finalFolder)) {
} else {
innerFoldersPaths.add(finalFolder);
}
}
}
}
for (String backSlashName : innerFoldersPaths) {
retEntries.add(zipFile.getEntry(backSlashName));
}
zipFile.close();
return retEntries;
} catch (Exception exception) {
// handle the exception in the way you want.
exception.printStackTrace();
}
return null;
}
The usage of this method:
File file = new File("Your zip file here");
for (ZipEntry zipEntry : getZipContent(file, 1)) { // This would return all the folders in the first file
// Do what ever your wantt with the ZipEntry
System.out.println(zipEntry.getName());
}
If you want to get all the folders past the first one,
you could do it by changing the index to how deep the folders that you want to get are.
use this fun in Kotlin
fun getRootFolderName(fileAddress: String): String {
if (File(fileAddress).parent == null || ("" + File(fileAddress).parent).length < 1) return File(fileAddress).name
return getRootFolderName("" + File(fileAddress).parent)
}
given a zip file with multiple nested directory structure, how do I unzip it into the same tree structure?
does ZipFile.entries() provide the enumeration in any order?
This is mine.
In file you specify the file you want to expand
in target dir you have to specify the target location as "new File("/tmp/foo/bar")". If you want to extract in the current directory you can specify targetDir = new File(".")
public static void unzip(File file, File targetDir) throws ZipException,
IOException {
targetDir.mkdirs();
ZipFile zipFile = new ZipFile(file);
try {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
File targetFile = new File(targetDir, entry.getName());
if (entry.isDirectory()) {
targetFile.mkdirs();
} else {
InputStream input = zipFile.getInputStream(entry);
try {
OutputStream output = new FileOutputStream(targetFile);
try {
copy(input, output);
} finally {
output.close();
}
} finally {
input.close();
}
}
}
} finally {
zipFile.close();
}
}
private static void copy(InputStream input, OutputStream output)
throws IOException {
byte[] buffer = new byte[4096];
int size;
while ((size = input.read(buffer)) != -1)
output.write(buffer, 0, size);
}
Worked for me. Good luck.
Here's the one I use all the times. It should directly work after a copy/paste and in any circumstances.
public static File unzip(File inFile, File outFolder)
{ final int BUFFER = 2048;
try
{
BufferedOutputStream out = null;
ZipInputStream in = new ZipInputStream(
new BufferedInputStream(
new FileInputStream(inFile)));
ZipEntry entry;
while((entry = in.getNextEntry()) != null)
{
//System.out.println("Extracting: " + entry);
int count;
byte data[] = new byte[BUFFER];
//We will try to reconstruct the entry directories
File entrySupposedPath = new File(outFolder.getAbsolutePath()+File.separator+entry.getName());
//Does the parent folder exist?
if (!entrySupposedPath.getParentFile().exists()){
entrySupposedPath.getParentFile().mkdirs();
}
// write the files to the disk
out = new BufferedOutputStream(
new FileOutputStream(outFolder.getPath() + "/" + entry.getName()),BUFFER);
while ((count = in.read(data,0,BUFFER)) != -1)
{
out.write(data,0,count);
}
out.flush();
out.close();
}
in.close();
return outFolder;
}
catch(Exception e)
{
e.printStackTrace();
return inFile;
}
}
Zip doesn't offer directory structure per se. The tree alike structure is built by having full path of each entry. ZipFile enumerates the entries in the same way they have been added to the file.
Note: java.util.ZipEntry.isDirectory() just tests if the last character of the name is '/', that's how it works.
What you need to extract the files into the same directory. Parse then name like that:
for(ZipEntry zipEntry : java.util.Collections.list(zipFile.entries())){//lazislav
String name = zipEntry.getName();
int idx = name.lastIndexOf('/');
if (idx>=0) name=name.substring(idx)
if (name.length()==0) continue;
File f = new File(targetDir, name);
}
That shall do it more or less (you still need to take care of duplicate file names, etc)
ZipFile zipFile = new ZipFile("archive.zip");
try {
for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements();) {
ZipEntry entry = entries.nextElement();
if (entry.isDirectory()) {
new File(entry.getName()).mkdirs();
} else {
InputStream in = zipFile.getInputStream(entry);
try {
OutputStream out = new BufferedOutputStream(new FileOutputStream(entry.getName()));
try {
// this util class is taken from apache commons io (see http://commons.apache.org/io/)
IOUtils.copy(in, out);
} finally {
out.close();
}
} finally {
in.close();
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
zipFile.close();
}
Why do you care about order?
If the ZipFile entry has a name /a/b/c/file.txt, then you can work out the directory name /a/b/c and then create a directory in your tree called a/b/c.
I have zip file which contains some other zip files.
For example, the mail file is abc.zip and it contains xyz.zip, class1.java, class2.java. And xyz.zip contains the file class3.java and class4.java.
So I need to extract the zip file using Java to a folder that should contain class1.java, class2.java, class3.java and class4.java.
Warning, the code here is ok for trusted zip files, there's no path validation before write which may lead to security vulnerability as described in zip-slip-vulnerability if you use it to deflate an uploaded zip file from unknown client.
This solution is very similar to the previous solutions already posted, but this one recreates the proper folder structure on unzip.
public static void extractFolder(String zipFile) throws IOException {
int buffer = 2048;
File file = new File(zipFile);
try (ZipFile zip = new ZipFile(file)) {
String newPath = zipFile.substring(0, zipFile.length() - 4);
new File(newPath).mkdir();
Enumeration<? extends ZipEntry> zipFileEntries = zip.entries();
// Process each entry
while (zipFileEntries.hasMoreElements()) {
// grab a zip file entry
ZipEntry entry = zipFileEntries.nextElement();
String currentEntry = entry.getName();
File destFile = new File(newPath, currentEntry);
File destinationParent = destFile.getParentFile();
// create the parent directory structure if needed
destinationParent.mkdirs();
if (!entry.isDirectory()) {
BufferedInputStream is = new BufferedInputStream(zip.getInputStream(entry));
int currentByte;
// establish buffer for writing file
byte[] data = new byte[buffer];
// write the current file to disk
FileOutputStream fos = new FileOutputStream(destFile);
try (BufferedOutputStream dest = new BufferedOutputStream(fos, buffer)) {
// read and write until last byte is encountered
while ((currentByte = is.read(data, 0, buffer)) != -1) {
dest.write(data, 0, currentByte);
}
dest.flush();
is.close();
}
}
if (currentEntry.endsWith(".zip")) {
// found a zip file, try to open
extractFolder(destFile.getAbsolutePath());
}
}
}
}
Here's some untested code base on some old code I had that unzipped files.
public void doUnzip(String inputZip, String destinationDirectory)
throws IOException {
int BUFFER = 2048;
List zipFiles = new ArrayList();
File sourceZipFile = new File(inputZip);
File unzipDestinationDirectory = new File(destinationDirectory);
unzipDestinationDirectory.mkdir();
ZipFile zipFile;
// Open Zip file for reading
zipFile = new ZipFile(sourceZipFile, ZipFile.OPEN_READ);
// Create an enumeration of the entries in the zip file
Enumeration zipFileEntries = zipFile.entries();
// Process each entry
while (zipFileEntries.hasMoreElements()) {
// grab a zip file entry
ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
String currentEntry = entry.getName();
File destFile = new File(unzipDestinationDirectory, currentEntry);
destFile = new File(unzipDestinationDirectory, destFile.getName());
if (currentEntry.endsWith(".zip")) {
zipFiles.add(destFile.getAbsolutePath());
}
// grab file's parent directory structure
File destinationParent = destFile.getParentFile();
// create the parent directory structure if needed
destinationParent.mkdirs();
try {
// extract file if not a directory
if (!entry.isDirectory()) {
BufferedInputStream is =
new BufferedInputStream(zipFile.getInputStream(entry));
int currentByte;
// establish buffer for writing file
byte data[] = new byte[BUFFER];
// write the current file to disk
FileOutputStream fos = new FileOutputStream(destFile);
BufferedOutputStream dest =
new BufferedOutputStream(fos, BUFFER);
// read and write until last byte is encountered
while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, currentByte);
}
dest.flush();
dest.close();
is.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
zipFile.close();
for (Iterator iter = zipFiles.iterator(); iter.hasNext();) {
String zipName = (String)iter.next();
doUnzip(
zipName,
destinationDirectory +
File.separatorChar +
zipName.substring(0,zipName.lastIndexOf(".zip"))
);
}
}
I take ca.anderson4 and remove the List zipFiles and rewrite a little bit, this is what i got:
public class Unzip {
public void unzip(String zipFile) throws ZipException,
IOException {
System.out.println(zipFile);;
int BUFFER = 2048;
File file = new File(zipFile);
ZipFile zip = new ZipFile(file);
String newPath = zipFile.substring(0, zipFile.length() - 4);
new File(newPath).mkdir();
Enumeration zipFileEntries = zip.entries();
// Process each entry
while (zipFileEntries.hasMoreElements()) {
// grab a zip file entry
ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
String currentEntry = entry.getName();
File destFile = new File(newPath, currentEntry);
destFile = new File(newPath, destFile.getName());
File destinationParent = destFile.getParentFile();
// create the parent directory structure if needed
destinationParent.mkdirs();
if (!entry.isDirectory()) {
BufferedInputStream is = new BufferedInputStream(zip
.getInputStream(entry));
int currentByte;
// establish buffer for writing file
byte data[] = new byte[BUFFER];
// write the current file to disk
FileOutputStream fos = new FileOutputStream(destFile);
BufferedOutputStream dest = new BufferedOutputStream(fos,
BUFFER);
// read and write until last byte is encountered
while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, currentByte);
}
dest.flush();
dest.close();
is.close();
}
if (currentEntry.endsWith(".zip")) {
// found a zip file, try to open
unzip(destFile.getAbsolutePath());
}
}
}
public static void main(String[] args) {
Unzip unzipper=new Unzip();
try {
unzipper.unzip("test/test.zip");
} catch (ZipException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I tested and it works
In testing I noticed File.mkDirs() does not work under Windows...
/**
* for a given full path name recreate all parent directories
**/
private void createParentHierarchy(String parentName) throws IOException {
File parent = new File(parentName);
String[] parentsStrArr = parent.getAbsolutePath().split(File.separator == "/" ? "/" : "\\\\");
//create the parents of the parent
for(int i=0; i < parentsStrArr.length; i++){
StringBuffer currParentPath = new StringBuffer();
for(int j = 0; j < i; j++){
currParentPath.append(parentsStrArr[j]+File.separator);
}
File currParent = new File(currParentPath.toString());
if(!currParent.isDirectory()){
boolean created = currParent.mkdir();
if(isVerbose)log("creating directory "+currParent.getAbsolutePath());
}
}
//create the parent itself
if(!parent.isDirectory()){
boolean success = parent.mkdir();
}
}
Modified as i needed then mixed in a bit of the best answers. This version will:
Recursively Extract a zip to given location
Create empty directories
Close zip properly
public static void unZipAll(File source, File destination) throws IOException
{
System.out.println("Unzipping - " + source.getName());
int BUFFER = 2048;
ZipFile zip = new ZipFile(source);
try{
destination.getParentFile().mkdirs();
Enumeration zipFileEntries = zip.entries();
// Process each entry
while (zipFileEntries.hasMoreElements())
{
// grab a zip file entry
ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
String currentEntry = entry.getName();
File destFile = new File(destination, currentEntry);
//destFile = new File(newPath, destFile.getName());
File destinationParent = destFile.getParentFile();
// create the parent directory structure if needed
destinationParent.mkdirs();
if (!entry.isDirectory())
{
BufferedInputStream is = null;
FileOutputStream fos = null;
BufferedOutputStream dest = null;
try{
is = new BufferedInputStream(zip.getInputStream(entry));
int currentByte;
// establish buffer for writing file
byte data[] = new byte[BUFFER];
// write the current file to disk
fos = new FileOutputStream(destFile);
dest = new BufferedOutputStream(fos, BUFFER);
// read and write until last byte is encountered
while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, currentByte);
}
} catch (Exception e){
System.out.println("unable to extract entry:" + entry.getName());
throw e;
} finally{
if (dest != null){
dest.close();
}
if (fos != null){
fos.close();
}
if (is != null){
is.close();
}
}
}else{
//Create directory
destFile.mkdirs();
}
if (currentEntry.endsWith(".zip"))
{
// found a zip file, try to extract
unZipAll(destFile, destinationParent);
if(!destFile.delete()){
System.out.println("Could not delete zip");
}
}
}
} catch(Exception e){
e.printStackTrace();
System.out.println("Failed to successfully unzip:" + source.getName());
} finally {
zip.close();
}
System.out.println("Done Unzipping:" + source.getName());
}
One should CLOSE zip file after unzip.
static public void extractFolder(String zipFile) throws ZipException, IOException
{
System.out.println(zipFile);
int BUFFER = 2048;
File file = new File(zipFile);
ZipFile zip = new ZipFile(file);
try
{
...code from other answers ( ex. NeilMonday )...
}
finally
{
zip.close();
}
}
Same as NeilMonday's answer, but extracts empty directories:
static public void extractFolder(String zipFile) throws ZipException, IOException
{
System.out.println(zipFile);
int BUFFER = 2048;
File file = new File(zipFile);
ZipFile zip = new ZipFile(file);
String newPath = zipFile.substring(0, zipFile.length() - 4);
new File(newPath).mkdir();
Enumeration zipFileEntries = zip.entries();
// Process each entry
while (zipFileEntries.hasMoreElements())
{
// grab a zip file entry
ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
String currentEntry = entry.getName();
File destFile = new File(newPath, currentEntry);
//destFile = new File(newPath, destFile.getName());
File destinationParent = destFile.getParentFile();
// create the parent directory structure if needed
destinationParent.mkdirs();
if (!entry.isDirectory())
{
BufferedInputStream is = new BufferedInputStream(zip
.getInputStream(entry));
int currentByte;
// establish buffer for writing file
byte data[] = new byte[BUFFER];
// write the current file to disk
FileOutputStream fos = new FileOutputStream(destFile);
BufferedOutputStream dest = new BufferedOutputStream(fos,
BUFFER);
// read and write until last byte is encountered
while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, currentByte);
}
dest.flush();
dest.close();
is.close();
}
else{
destFile.mkdirs()
}
if (currentEntry.endsWith(".zip"))
{
// found a zip file, try to open
extractFolder(destFile.getAbsolutePath());
}
}
}
Here is some code, which I tested to be working quite well :
package com.test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class Unzipper {
private final static int BUFFER_SIZE = 2048;
private final static String ZIP_FILE = "/home/anton/test/test.zip";
private final static String DESTINATION_DIRECTORY = "/home/anton/test/";
private final static String ZIP_EXTENSION = ".zip";
public static void main(String[] args) {
System.out.println("Trying to unzip file " + ZIP_FILE);
Unzipper unzip = new Unzipper();
if (unzip.unzipToFile(ZIP_FILE, DESTINATION_DIRECTORY)) {
System.out.println("Succefully unzipped to the directory "
+ DESTINATION_DIRECTORY);
} else {
System.out.println("There was some error during extracting archive to the directory "
+ DESTINATION_DIRECTORY);
}
}
public boolean unzipToFile(String srcZipFileName,
String destDirectoryName) {
try {
BufferedInputStream bufIS = null;
// create the destination directory structure (if needed)
File destDirectory = new File(destDirectoryName);
destDirectory.mkdirs();
// open archive for reading
File file = new File(srcZipFileName);
ZipFile zipFile = new ZipFile(file, ZipFile.OPEN_READ);
//for every zip archive entry do
Enumeration<? extends ZipEntry> zipFileEntries = zipFile.entries();
while (zipFileEntries.hasMoreElements()) {
ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
System.out.println("\tExtracting entry: " + entry);
//create destination file
File destFile = new File(destDirectory, entry.getName());
//create parent directories if needed
File parentDestFile = destFile.getParentFile();
parentDestFile.mkdirs();
if (!entry.isDirectory()) {
bufIS = new BufferedInputStream(
zipFile.getInputStream(entry));
int currentByte;
// buffer for writing file
byte data[] = new byte[BUFFER_SIZE];
// write the current file to disk
FileOutputStream fOS = new FileOutputStream(destFile);
BufferedOutputStream bufOS = new BufferedOutputStream(fOS, BUFFER_SIZE);
while ((currentByte = bufIS.read(data, 0, BUFFER_SIZE)) != -1) {
bufOS.write(data, 0, currentByte);
}
// close BufferedOutputStream
bufOS.flush();
bufOS.close();
// recursively unzip files
if (entry.getName().toLowerCase().endsWith(ZIP_EXTENSION)) {
String zipFilePath = destDirectory.getPath() + File.separatorChar + entry.getName();
unzipToFile(zipFilePath, zipFilePath.substring(0,
zipFilePath.length() - ZIP_EXTENSION.length()));
}
}
}
bufIS.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
I tried with the top voted answer here, and that does not recursively unzip the files, it just unzips the files of the first level.
Source : Solution which extracts files into a given directory
Also, check this solution by the same person : Solution which extracts file in memory
No third-party dependencies, guards against zip slip, fully commented, recreates directory structure recursively, ignores empty directories, sane source code nesting, extracts to zip file's directory, and uses UTF-8. Usage:
Path zipFile = Path.of( "/path/to/filename.zip" );
Zip.extract( zipFile );
Here's the code:
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import static java.nio.file.Files.createDirectories;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
/**
* Responsible for managing zipped archive files.
*/
public final class Zip {
/**
* Extracts the contents of the zip archive into its current directory. The
* contents of the archive must be {#link StandardCharsets#UTF_8}. For
* example, if the {#link Path} is <code>/tmp/filename.zip</code>, then
* the contents of the file will be extracted into <code>/tmp</code>.
*
* #param zipPath The {#link Path} to the zip file to extract.
* #throws IOException Could not extract the zip file, zip entries, or find
* the parent directory that contains the path to the
* zip archive.
*/
public static void extract( final Path zipPath ) throws IOException {
assert !zipPath.toFile().isDirectory();
try( final var zipFile = new ZipFile( zipPath.toFile() ) ) {
iterate( zipFile );
}
}
/**
* Extracts each entry in the zip archive file.
*
* #param zipFile The archive to extract.
* #throws IOException Could not extract the zip file entry.
*/
private static void iterate( final ZipFile zipFile )
throws IOException {
// Determine the directory name where the zip archive resides. Files will
// be extracted relative to that directory.
final var path = getDirectory( zipFile );
final var entries = zipFile.entries();
while( entries.hasMoreElements() ) {
final var zipEntry = entries.nextElement();
final var zipEntryPath = path.resolve( zipEntry.getName() );
// Guard against zip slip.
if( zipEntryPath.normalize().startsWith( path ) ) {
extract( zipFile, zipEntry, zipEntryPath );
}
}
}
/**
* Extracts a single entry of a zip file to a given directory. This will
* create the necessary directory path if it doesn't exist. Empty
* directories are not re-created.
*
* #param zipFile The zip archive to extract.
* #param zipEntry An entry in the zip archive.
* #param zipEntryPath The file location to write the zip entry.
* #throws IOException Could not extract the zip file entry.
*/
private static void extract(
final ZipFile zipFile,
final ZipEntry zipEntry,
final Path zipEntryPath ) throws IOException {
// Only attempt to extract files, skipping empty directories.
if( !zipEntry.isDirectory() ) {
createDirectories( zipEntryPath.getParent() );
try( final var in = zipFile.getInputStream( zipEntry ) ) {
Files.copy( in, zipEntryPath, REPLACE_EXISTING );
}
}
}
/**
* Helper method to return the normalized directory where the given archive
* resides.
*
* #param zipFile The {#link ZipFile} having a path to normalize.
* #return The directory containing the given {#link ZipFile}.
* #throws IOException The zip file has no parent directory.
*/
private static Path getDirectory( final ZipFile zipFile ) throws IOException {
final var zipPath = Path.of( zipFile.getName() );
final var parent = zipPath.getParent();
if( parent == null ) {
throw new IOException( zipFile.getName() + " has no parent directory." );
}
return parent.normalize();
}
}
Now that you have the core algorithm in place, you need to check the file extension for ".zip" and, if present, recursively call Zip.extract( ... ) on that file.
File dir = new File("BASE DIRECTORY PATH");
FileFilter ff = new FileFilter() {
#Override
public boolean accept(File f) {
//only want zip files
return (f.isFile() && f.getName().toLowerCase().endsWith(".zip"));
}
};
File[] list = null;
while ((list = dir.listFiles(ff)).length > 0) {
File file1 = list[0];
//TODO unzip the file to the base directory
}
I get the following IOException :
java.io.IOException: Access is denied
at java.io.WinNTFileSystem.createFileExclusively(Native Method)
at java.io.File.createNewFile(File.java:850)
at zipUnzipper.main(zipUnzipper.java:41)
When trying to run the following piece of code :
public class zipUnzipper {
public zipUnzipper() {
}
public static void main(String[] args){
//Unzip to temp folder. Add all files to mFiles. Print names of all files in mFfiles.
File file = new File("C:\\aZipFile.zip");
String filename = file.getName();
String filePathName = new String();
int o = filename.lastIndexOf('.');
filename = filename.substring(0,o);
try {
ZipFile zipFile = new ZipFile (file.getAbsoluteFile());
Enumeration entries = zipFile.entries();
while(entries.hasMoreElements()) {
ZipEntry zipEntry = (ZipEntry) entries.nextElement();
System.out.println("Unzipping: " + zipEntry.getName());
BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(zipEntry));
byte[] buffer = new byte[2048];
filePathName = "C:\\TEMP\\"+filename+"\\";
File fileToWrite = new File(filePathName+ zipEntry.getName());
fileToWrite.mkdirs();
fileToWrite.createNewFile();
FileOutputStream fos = new FileOutputStream(fileToWrite);
BufferedOutputStream bos = new BufferedOutputStream( fos , buffer.length );
int size;
while ((size = bis.read(buffer, 0, buffer.length)) != -1) {
bos.write(buffer, 0, size);
}
bos.flush();
bos.close();
bis.close();
}
zipFile.close();
File folder = new File (filePathName);
File [] mFiles = folder.listFiles();
for (int x=0; x<mFiles.length; x++) {
System.out.println(mFiles[x].getAbsolutePath());
}
} catch (ZipException ze) {
ze.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
It seems to me that for some reason the JVM can't create a new file. The code runs perfectly well if the files already exist. Is there some kind of access file which dictates whether the JVM can create a new file or am I simply doing something wrong?
Any help is much appreciated :-)
I'm running Java 1.4 and have been testing in JDeveloper in Windows XP.
The issue is that these calls step on each other:
fileToWrite.mkdirs(); //creates a directory e.g. C:\temp\foo\x
fileToWrite.createNewFile(); //attempts to create a file C:\temp\foo\x
The create operation fails because you just created a directory with the same name than the file you want to create.
What you want to do instead is:
fileToWrite.getParentFile().mkdirs()
And also, the call to createNewFile() is unnecessary.
Based on your code. The following "unzips" a zip file:
import java.io.*;
import java.util.zip.ZipFile;
import java.util.zip.ZipEntry;
import java.util.Enumeration;
public class Unzipper {
public static void main(String[] args)
throws IOException {
final File file = new File(args[0]);
final ZipFile zipFile = new ZipFile(file);
final byte[] buffer = new byte[2048];
final File tmpDir = new File(System.getProperty("java.io.tmpdir"), zipFile.getName());
if(!tmpDir.mkdir() && tmpDir.exists()) {
System.err.println("Cannot create: " + tmpDir);
System.exit(0);
}
for(final Enumeration entries = zipFile.entries(); entries.hasMoreElements();) {
final ZipEntry zipEntry = (ZipEntry) entries.nextElement();
System.out.println("Unzipping: " + zipEntry.getName());
final InputStream is = zipFile.getInputStream(zipEntry);
final File fileToWrite = new File(tmpDir, zipEntry.getName());
final File folder = fileToWrite.getParentFile();
if(!folder.mkdirs() && !folder.exists()) {
System.err.println("Cannot create: " + folder);
System.exit(0);
}
if(!zipEntry.isDirectory()) {
//No need to use buffered streams since we're doing our own buffering
final FileOutputStream fos = new FileOutputStream(fileToWrite);
int size;
while ((size = is.read(buffer)) != -1) {
fos.write(buffer, 0, size);
}
fos.close();
is.close();
}
}
zipFile.close();
}
}
Disclaimer: I haven't tested it beyond the very basics.
Why are you calling createNewFile()? Just create the FileOutputStream.
It also could be that in context where you are launching the application you haven't access rights to the place where you are trying to create the file. Launch the app as admin or create the file in the project folder.