zip a folder structure using java - java

I am trying to zip the following file structure on my machine,
parent/
parent/test1
parent/test1/image1.jpeg
parent/test2
The problem here is i cant zip the above file structure using java. I have google and found following code sample but it only zip the files only inside a given folder.
File inFolder=new File("out");
File outFolder=new File("Out.zip");
ZipOutputStream out = new ZipOutputStream(new
BufferedOutputStream(new FileOutputStream(outFolder)));
BufferedInputStream in = null;
byte[] data = new byte[1000];
String files[] = inFolder.list();
for (int i=0; i<files.length; i++)
{
in = new BufferedInputStream(new FileInputStream
(inFolder.getPath() + "/" + files[i]), 1000);
out.putNextEntry(new ZipEntry(files[i]));
int count;
while((count = in.read(data,0,1000)) != -1)
{
out.write(data, 0, count);
}
out.closeEntry();
}
out.flush();
out.close();
In the above code the out is a folder and we need to have some files..also folder cannot be empty if so it throws a exception java.util.zip.ZipException or cant contain any sub folders even files inside it (eg:out\newfolder\image.jpeg) if so it throws a java.io.FileNotFoundException: out\newfolder (Access is denied).
In my case im costructig the above file structure by quering the database sometime empty folders along the folder structure can be have.
Can some one please tell me a solution?
Thank You.

What is probably happening is that you're trying to treat every entry as a FileInputStream. However, for a directory, this is not true. Since the path is not to a file, when you try to read it, a FileNotFoundException is thrown. For directories, you still want to create the ZipEntry, but instead of trying to read in any data, just skip it and move on to the next path.

write two methods. The first one takes dirpath, makes a zip stream and calls another method which copies files to the zip stream and calls itself recursively for directories as below:
open an entry in the zip stream for the given directory
list files and dirs in the given directory, loop through them
if an entry is a file, open an entry, copy file content to the entry, close it
if an entry is a directory, call this method. Pass the zip stream
close the entry.
The first method closes the zip stream.

Related

Google Drive API not downloading FIles (Java v3)

I'm using the code from here:
https://developers.google.com/drive/api/v3/manage-downloads#downloading_a_file
The code snippet I'm using is the following and placed in the main method:
String fileId = "some file ID";
OutputStream outputStream = new ByteArrayOutputStream();
driveService.files().get(fileId)
.executeMediaAndDownloadTo(outputStream);
I have found no sign of the code actually downloading the file, nor do I know where the file is IF it actually downloads.
I'm not sure if I am using the proper scope to gain permission to download files. I am able to upload, list, and delete files as long as I know the fileID, but downloading seems to not work.
private static final List<String> SCOPES = Collections.singletonList(DriveScopes.DRIVE);
Alternatively, I'm trying to create a method to enact the download protocol like so:
private static void downloadFile(Drive service, File file (or String fileID)){
}
but am not sure on how to do so. I've tried looking for samples online but most are from v1 or v2 apis and don't seem to work for me.
Also, I've read somewhere that it is not possible to download a Folder. Instead, I have to download each item in the folder one by one.
So do I have to make an Arraylist/list/array of the fileIDs and iterate through it after initializing a variable to represent fileID?
Edit: Some progress has been made, but I still have some problems I'm trying to thrash out.
List<File> files = result.getFiles();
File newFile;
if (files == null || files.isEmpty()) {
System.out.println("No files found.");
} else {
System.out.println("Files:");
for (File file : files) {
System.out.printf("%s (%s)\n", file.getName(), file.getId());
String fileId = file.getId();
//System.out.println(fileId);
String fileName = file.getName();
//System.out.println(fileName);
OutputStream outputstream = new FileOutputStream();
service.files().get(fileId)
.executeMediaAndDownloadTo(outputstream);
outputstream.flush();
outputstream.close();
}
What I want:
The above code is in the main method. I don't know if this is the proper way to do it, but as the program fetches each file and executes the System.out.printf, I also want it to download that file (with the same mimeType, and pref the same name too) into the destination set in the OutputStream constructor (C://User//some name//Downloads).
What I've tried:
From what I've tested, it only downloads the first file exactly the way I want, but only because I specify the name and extension in OutputStream. I've initialized variables 'fileId' and 'fileName' so that they will change according to the info as the program fetches the metadata for the next file, but I don't know how to change or set multiple constructors into this code:
OutputStream outputstream = new FileOutputStream();
service.files().get(fileId)
.executeMediaAndDownloadTo(outputstream);
to download all the files.
My folder hierarchy in Google Drive is like this:
Logs
-- bin (folder)
---- bunch of .bin files
-- .xml file
-- .xml file
You are using a ByteArrayOutputStream object as the output of your download. If your program terminates without having saved the contents of this object somewhere, you will not be able to find this information in your computer's disk, as it is not written to it but rather saved in memory as a buffered byte-array (refer to the previous link for more information).
If you want to save the output of the download to the file, I suggest you use instead a FileOutputStream as the destination of your download. In order to do that, you have to modify your code as follows:
Add the appropriate import declaration:
import java.io.FileOutputStream;
Modify your outputStream variable assignment as follows:
OutputStream outputStream = new FileOutputStream('/tmp/downloadedfile');
Where the parameter passed to FileOutputStream should be the desired destination path of your download.
After writing any contents to your file, add the following lines of code:
outputStream.flush();
outputStream.close();
This will ensure that your file is being written to properly.
In regards to downloading a folder, you are completely right - you will first need to fetch the folder you want to download, and each of their children. In order to better understand how to do it, I suggest you check out the following answer: Download folder with Google Drive API
Edit - example downloading a folder
String destinationFolder = "/tmp/downloadedfiles/";
List<File> files = result.getFiles();
File newFile;
if (files == null || files.isEmpty()) {
System.out.println("No files found.");
} else {
System.out.println("Files:");
for (File file : files) {
System.out.printf("%s (%s)\n", file.getName(), file.getId());
String fileId = file.getId();
String fileName = file.getName();
OutputStream outputstream = new FileOutputStream(destinationFolder + fileName);
service.files().get(fileId)
.executeMediaAndDownloadTo(outputstream);
outputstream.flush();
outputstream.close();
}
}

Read the data from TXT file inside Zip File without extracting the contents in Matlab

I have tab delimited ascii data in txt files which are zip compressed (and the zip may or may not contain other files). I would like to read this data into a matrix without uncompressing the zip files.
There were a few similar #matlab / #java posts earlier:
Read the data of CSV file inside Zip File without extracting the contents in Matlab
Extracting specific file from zip in matlab
Read Content from Files which are inside Zip file
I have gotten this far thanks to the above - I can identify the .txt inside the zip, but don't know how to actually read its contents. First example:
zipFilename = 'example.zip';
zipJavaFile = java.io.File(zipFilename);
zipFile=org.apache.tools.zip.ZipFile(zipJavaFile);
entries=zipFile.getEntries;
cnt=1;
while entries.hasMoreElements
tempObj=entries.nextElement;
file{cnt,1}=tempObj.getName.toCharArray';
cnt=cnt+1;
end
ind=regexp(file,'$*.xml$');
ind=find(~cellfun(#isempty,ind));
file=file(ind);
file = cellfun(#(x) fullfile('.',x),file,'UniformOutput',false);
% Now Operate Any thing on File.
zipFile.close
HOWEVER, I found no example as to how to "operate anything on file". I can extract the path within the zip file, but don't know how to actually read the contents of this txt file. (I wish to directly read its contents into memory -- a matrix --, without extraction, if possible.)
The other example is
zipFilename = 'example.zip';
zipFile = org.apache.tools.zip.ZipFile(zipFilename);
entries = zipFile.getEntries;
while entries.hasMoreElements
entry = entries.nextElement;
entryName = char(entry.getName);
[~,~,ext] = fileparts(entryName);
if strcmp(ext,'.txt')
inputStream = zipFile.getInputStream(entry);
%Read the contents of the file
inputStream.close;
end
end
zipFile.close
The original example contained code to extract the file, but I merely want to read it directly into memory. Again, I don't know how exactly to work with this inputStream.
Could anyone give me a suggestion with a MWE?
It might be a little late, but maybe someone can use it:
(the code was tested in Matlab R2018a)
zipFilename = 'example.zip';
zipFile = org.apache.tools.zip.ZipFile(zipFilename);
entries = zipFile.getEntries;
while entries.hasMoreElements
entry = entries.nextElement;
entryName = char(entry.getName);
[~,~,ext] = fileparts(entryName);
if strcmp(ext,'.txt')
inputStream = zipFile.getInputStream(entry);
%Read the contents of the file
buffer = java.io.ByteArrayOutputStream();
org.apache.commons.io.IOUtils.copy(inputStream, buffer);
data = char(typecast(buffer.toByteArray(), 'uint8')');
inputStream.close;
end
end
zipFile.close

Replacing files in multilevel zip folders

My requirement is to replace few files in a zip file.
The zip file in turn have multiple zip files and folder within it. It goes upto 4 or more levels of zip files.
I have a set of files in a different source directory. I would like to copy these files and replace within the zip file, by matching the file name in the source directory with file name inside the zip file.
Could someone help here please.
Thanks,
Deleep
One way is use temp files to store the ZIPs and open them as FileSystems, so you dont need to extrat all files and rezip everything
FileSystem firstZip = FileSystems.newFileSystem(URI.create("jar:file:/root/firstZip.zip"),
new HashMap<>(), null);
//Get a zip inside the first one
Path path = firstZip.getPath("FOLDER/ZIP_NAME.zip");
//Get the second zip input stream and store the zip in a temp file
InputStream in = firstZip.provider().newInputStream(path);
Path secondPath = Paths.get("/root/temp/tempFile.tmp");
Files.copy(in, secondPath);
//open the second zip
FileSystem secondZip = FileSystems.newFileSystem(new URI("jar:" + secondPath.toUri().toString()),
new HashMap<>(), null);
//iterate files in the second zip
DirectoryStream<Path> ds = Files.newDirectoryStream(secondPath);
for(Path p: ds){
//something
}
//delete or update files inside the second zip
//Files.delete(seconZip.getPath("aFile.txt"));
//Files.copy(anInputStream, secondZip.getPath("destFoldet/aFile.txt"));
//clse the seconzip
secondZip.close();
//update the second zip inside first one
Files.copy(secondPath, firstZip.provider().newOutputStream(path));
//delete temp file
Files.delete(secondPath);
//close first zip
firstZip.close();
Other idea is jboss-vfs. Never tried it, but i think that could help.

How can I access a non-class file inside a jar FROM 'within' the jar

This should be simple but it has cost me hours. Everything I find on this site indicates I am doing it right but the file still cannot be found.
Inside a jar file I have two files 'CDAkeystore.jks' and 'CDAtruststore.jks' at top level.
Yet when I call
securityProps.setProperty("javax.net.ssl.keyStore","CDAkeystore.jks");
I get a system cannot find the file requested error.
The class file calling this method is inside the same jar in the usual package arrangement.
The jar file is as follows:
com ..... (a lot more class files)
org ..... (lots of class files)
META-INF
CDAtruststore.jks
CDAkeystore.jks
How can this be SOOO difficult?!!
---------- Added INfo ------n
Since the object using the path is open source I found the routine they are using to load the file. It is:
InputStream keystoreInputStream = preBufferInputStream(new FileInputStream(keyStoreName));
which according to the documentation of FileInputStream(String name) is
Creates a FileInputStream by opening a connection to an actual file, the file named by the path name 'name' in the file system. So how should this path be expressed?
Use YourClass.class.getResourceAsStream() or this.getClass().getResourceAsStream(). You can also use class loader if you are in multiple class loaders environment.
The answer is, in short, that you can't. At least in this situation. I am stuck with passing a path to a file to a library implementation that I have no control over. So the library method accesses the file on the assumption that the file exists in unzipped form in the OS's file system. It is getting the path from a Property.setProperty(stringKey, stringPath)
So the only solution I found was an ugly hack. I need to take the resource in my jar and copy it to a file on the system. Then I would pass the path to that file in the above setProperty() method. The ugly hack is implemented as follows (if anyone else can come up with a nicer solution I would be happy). It does solve the problem. The library routine is able to find my newly created file.
/* This evil reads a file as a resource inside a jar and dumps the file where ever
* the loader of this jar/application defines as the current directory. This pain is done
* so the SecurityDomian class can load the file; it cannot access the file from
* the jar. This means the 'name' passed in contains the file name inside the jar
* prefixed with "/" so it is not read with an assumed package extension.
*/
private boolean createFileFromResource(String name)
{
// Dont bother if the file already exists
if(new File(name.replace("/", "")).exists())
{
return true;
}
byte[] keystoreFile = new byte[2048];
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(2048);
// Get the resource
InputStream inputStream = this.getClass().getResourceAsStream(name);
try
{
int bytesRead = 0;
while(true)
{
// Read the resource into the buffer keystoreFile in 2048 byte chunks
bytesRead = inputStream.read(keystoreFile);
if(bytesRead < 0)
{
break;
}
// Copy and append the chunks to the ByteArrayOutputStream (this class
// does the auto-extending of the output array as more chunks are
// added so you don't have to do it.
byteArrayOut.write(keystoreFile, 0, bytesRead);
}
inputStream.close();
// Now create a file at the root of where ever the loader happens to think
// the root is. So remove the "/" in front of the file name
FileOutputStream outputStream = new FileOutputStream(name.replace("/", ""));
// Write out the file. Note you will be left with garbage at that location.
byteArrayOut.writeTo(outputStream);
outputStream.flush();
outputStream.close();
}
catch (IOException e)
{
e.printStackTrace();
return false;
}
return true;
}

how to check if a ZIP file is empty in Java?

I have the following piece of code -
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(outputStream);
for (int i = 0; i < params.getGrades().size(); i++) {
generateReport(param1, param2, zos);
}
zos.flush();
zos.close();
In the generateReport method, I have code to generate my reports as xls files and add them to ZIP.
Is there any way we can check if any files have been written in the ZIP file, or if the ZIP file is empty? is there any property I can use?
Thanks,
Raaz
You can use the ZipFile from the java.util.zip package.
You can invoke the
size()
method.
After you close zos, outputStream.size() gives you the number of bytes written. You would have to allow for whatever the ZIP header size is for an empty ZIP file.
See:
http://www.java-examples.com/get-number-entries-zip-file-example
and:
Count files in ZIP's directory - JAVA, Android
and:
Android: Get Number of Files within Zip?
#Raaz, Please go through this link.
In that you can see a Class called 'ZipEntry'. It represents the files contained in a zip folder. It provides some useful methods such as:
zipEntry.getName(); // name of the file contained by zip.
zipEntry.getSize(); // size of the file contained by zip.
#Didier - I decided to take your advice on returning a value, but ended up doing it this way -
Instead of checking if a file has been added to the ZIP, I checked if the list data I'm trying to write in an xls file (the file which in turn gets added to the ZIP) is empty. If it's empty, then I set a error value to "No file generated". If the list is not empty, I assigned the an empty value to the string and returned it to the calling function.

Categories