The following unzip finction doesn't work for all zip files.
My zip file pattern is as follows-
The Zip file contains one xml file and one folder(name- "images").
The name of the xml file is same as the zip file name.
The folder("images") may or may not contain any files.
I have validated the xml file before putting it into the zip file.
It throws exception at this line for some zip files-
FileOutputStream fout = new ileOutputStream(path.substring(0,path.length()-4)+"/"+filename);
The function is:
public boolean unZip(String path)
{
InputStream is;
ZipInputStream zis;
try
{
String filename;
is = new FileInputStream(path);
zis = new ZipInputStream(new BufferedInputStream(is));
ZipEntry ze;
byte[] buffer = new byte[1024];
int count;
while ((ze = zis.getNextEntry()) != null)
{
filename = ze.getName();
if (ze.isDirectory()) {
File fmd = new File(path.substring(0,path.length()-4)+"/"+filename);
fmd.mkdirs();
continue;
}
FileOutputStream fout = new FileOutputStream(path.substring(0,path.length()-4)+"/"+filename);
while ((count = zis.read(buffer)) != -1)
{
fout.write(buffer, 0, count);
}
fout.close();
zis.closeEntry();
}
zis.close();
}
catch(IOException e)
{
e.printStackTrace();
return false;
}
return true;
}
This method works fine. It was a permission issue while creating the zips in Linux platform. But function starts working properly when I changed the file permission.
Related
I have android app that downloads compressed files and then decompress it ..
it works fine with English name files..
but if the file with Arabic name it make error malformated
E/UncaughtException: java.lang.IllegalArgumentException: MALFORMED[1]
this is my code..
appreciate your help
Thanks
private boolean unpackZip(String path, String zipname)
{
InputStream is;
ZipInputStream zis;
try
{
String filename;
is = new FileInputStream(path + zipname);
zis = new ZipInputStream(new BufferedInputStream(is));
ZipEntry ze;
byte[] buffer = new byte[1024];
int count;
while ((ze = zis.getNextEntry()) != null)
{
filename = ze.getName();
// Need to create directories if not exists, or
// it will generate an Exception...
if (ze.isDirectory()) {
File fmd = new File(path + filename);
fmd.mkdirs();
continue;
}
FileOutputStream fout = new FileOutputStream(path + filename);
while ((count = zis.read(buffer)) != -1)
{
fout.write(buffer, 0, count);
}
fout.close();
zis.closeEntry();
}
zis.close();
}
catch(IOException e)
{
e.printStackTrace();
return false;
}
return true;
}
Try
new ZipInputStream(new BufferedInputStream(is), Charset.forName("Windows-1256"));
as default is UTF-8 and that evidently did not work.
After feedback: evidently there is some Android API version problem.
You could inspect:
filename = ze.getName();
Sometimes one can "patch" the encoding. Very error prone, or even not feasible.
filename = new String(filename.getBytes("..."), "...");
where one might try different encodings:
Windows-1256
UTF-8
(Especially converting to UTF-8 might raise conversion errors, as UTF-8 requires the bytes to have a specific bit pattern for multibyte sequences.)
We are storing zip files, containing XML files, in HDFS. We need to be able to programmatically unzip the file and stream out the contained XML files, using Java. FileSystem.open returns a FSDataInputStream but ZipFile constructors only take File or String as parameters. I really don't want to have to use FileSystem.copyToLocalFile.
Is it possible to stream the contents of a zip file stored in HDFS without first copying the zip file to the local file system? If so how?
Hi Please find the sample code,
public static Map<String, byte[]> loadZipFileData(String hdfsFilePath) {
try {
ZipInputStream zipInputStream = readZipFileFromHDFS(new Path(hdfsFilePath));
ZipEntry zipEntry = null;
byte[] buf = new byte[1024];
Map<String, byte[]> listOfFiles = new LinkedHashMap<>();
while ((zipEntry = zipInputStream.getNextEntry()) != null ) {
int bytesRead = 0;
String entryName = zipEntry.getName();
if (!zipEntry.isDirectory()) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
while ((bytesRead = zipInputStream.read(buf, 0, 1024)) > -1) {
outputStream.write(buf, 0, bytesRead);
}
listOfFiles.put(entryName, outputStream.toByteArray());
outputStream.close();
}
zipInputStream.closeEntry();
}
zipInputStream.close();
return listOfFiles;
} catch (Exception e) {
e.printStackTrace();
}
}
protected ZipInputStream readZipFileFromHDFS(FileSystem fileSystem, Path path) throws Exception {
if (!fileSystem.exists(path)) {
throw new IllegalArgumentException(path.getName() + " does not exist");
}
FSDataInputStream fsInputStream = fileSystem.open(path);
ZipInputStream zipInputStream = new ZipInputStream(fsInputStream);
return zipInputStream;
}
Here i have folder(ZipFilesFolder) in that it consist of 10 zip files say one.zip,two.zip,three.zip..ten.zip,i'm passing file every time from this folder to zipFileToUnzip as zipFilename.I need the result in the same folder(ZipFilesFolder)i need to unzip those files and instead of one.zip,two.zip,..one,two,three folder has to visible.
public static void zipFileToUnzip(File zipFilename) throws IOException {
try {
//String destinationname = "D:\\XYZ";
byte[] buf = new byte[1024];
ZipInputStream zipinputstream = null;
ZipEntry zipentry;
zipinputstream = new ZipInputStream(new FileInputStream(zipFilename));
zipentry = zipinputstream.getNextEntry();
while (zipentry != null) {
//for each entry to be extracted
String entryName = zipentry.getName();
System.out.println("entryname " + entryName);
int n;
FileOutputStream fileoutputstream;
File newFile = new File(entryName);
String directory = newFile.getParent();
if (directory == null) {
if (newFile.isDirectory()) {
break;
}
}
fileoutputstream = new FileOutputStream(
destinationname + entryName);
while ((n = zipinputstream.read(buf, 0, 1024)) > -1) {
fileoutputstream.write(buf, 0, n);
}
fileoutputstream.close();
zipinputstream.closeEntry();
zipentry = zipinputstream.getNextEntry();
}//while
zipinputstream.close();
} catch (IOException e) {
}
}
This is my code ,but it is not working,could anybody help me,how to get desired output.
There are a couple of problems with your code:
it does not compile since destinationname is commented, but referenced when opening the FileOutputStream
IOExceptions are caught and ignored. If you throw them you would get error messages that could help you diagnose the problem
when opening the FileOutputStream, you just concatenate two strings without adding a path-separator in between.
if the file to be created is in a directory, the directory is not created and thus FileOutputStream cannot create the file.
streams are not closed when exceptions occur.
If you do not mind using guava, which simplifies life when it comes to copying streams to files, you could use this code instead:
public static void unzipFile(File zipFile) throws IOException {
File destDir = new File(zipFile.getParentFile(), Files.getNameWithoutExtension(zipFile.getName()));
try(ZipInputStream zipStream = new ZipInputStream(new FileInputStream(zipFile))) {
ZipEntry zipEntry = zipStream.getNextEntry();
if(zipEntry == null) throw new IOException("Empty or no zip-file");
while(zipEntry != null) {
File destination = new File(destDir, zipEntry.getName());
if(zipEntry.isDirectory()) {
destination.mkdirs();
} else {
destination.getParentFile().mkdirs();
Files.asByteSink(destination).writeFrom(zipStream);
}
zipEntry = zipStream.getNextEntry();
}
}
}
Alternatively you might also use zip4j, see also this question.
I have a problem when I try to unzip file contains files with special characters.
Lets say I have a zip file gallery.zip with image files.
gallery.zip
- file01.jpg
- dařbuján.jpg
My method starts:
public List<File> unzipToTemporaryFolder(ZipInputStream inputStream)
throws IOException {
List<File> files = new LinkedList<File>();
ZipEntry entry = null;
int count;
byte[] buffer = new byte[BUFFER];
while ((entry = inputStream.getNextEntry()) != null) {
It fails in inputStream.getNextEntry() when I try to read file dařbuján.jpg because of czech letters "ř" and "á". It works well with the other files for example with spaces (104 25.jpg or simply file.jpg etc.). Can you help me please?
Create your ZipInputStream with Charset specified using
ZipInputStream(InputStream in, Charset charset)
like
new ZipInputStream(inputStream, Charset.forName("UTF-8"));
Ok, I solved it with commons-compress. If somebody is interested here is my method:
public List<File> unzipToTemporaryFolder(ZipInputStream inputStream,
File tempFile) throws IOException {
List<File> files = new LinkedList<File>();
int count;
byte[] buffer = new byte[BUFFER];
org.apache.commons.compress.archivers.zip.ZipFile zf = new org.apache.commons.compress.archivers.zip.ZipFile(tempFile, "UTF-8");
Enumeration<?> entires = zf.getEntries();
while(entires.hasMoreElements()) {
org.apache.commons.compress.archivers.zip.ZipArchiveEntry entry = (org.apache.commons.compress.archivers.zip.ZipArchiveEntry)entires.nextElement();
if(entry.isDirectory()) {
unzipDirectoryZipEntry(files, entry);
} else {
InputStream zin = zf.getInputStream(entry);
File temp = File.createTempFile(entry.getName().substring(0, entry.getName().length() - 4) + "-", "." + entry.getName().substring(entry.getName().length() - 3, entry.getName().length()));
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(temp), BUFFER);
while ((count = zin.read(buffer, 0, BUFFER)) != -1) {
outputStream.write(buffer, 0, count);
}
outputStream.flush();
zin.close();
outputStream.close();
files.add(temp);
}
}
zf.close();
return files;
}
Simple question,
I'm writing a series of text files into a zip, just wrapping a fileoutputstream in a zipoutputstream and then in a printwriter.
public static int saveData(File outfile, DataStructure input) {
//variables
ArrayList<String> out = null;
FileOutputStream fileout = null;
ZipOutputStream zipout = null;
PrintWriter printer = null;
//parameter tests
try {
fileout = new FileOutputStream(outfile);
zipout = new ZipOutputStream(fileout);
printer = new PrintWriter(zipout);
} catch (Exception e) {
e.printStackTrace();
return util.FILE_INVALID;
}
for(DataItem data : input){
//process the data into a list of strings
try {
zipout.putNextEntry(new ZipEntry( dataFileName ));
for(String s : out) {
printer.println(s);
}
zipout.closeEntry();
} catch (Exception e) {
try {
fileout.close();
} catch (Exception x) {
x.printStackTrace();
return util.CRITICAL_ERROR;
}
e.printStackTrace();
return util.CRITICAL_ERROR;
}
}
try {
fileout.close();
} catch (Exception e) {
e.printStackTrace();
return util.CRITICAL_ERROR;
}
return util.SUCCESS;
}
Previously in the app i've been developing I've just been saving to the current directory for testing and I know in the case of a file already existing that the file will be overwritten (and have been exploiting this). What I dont know is the behaviour for zips. Will it overwrite entries of the same name? Or will it simply overwrite the whole zip file (which would be convenient for my purposes.
K.Barad
As Joel said, If you try to add a duplicate ZipEntry you will get an exception. If you want to replace the current entry you need to delete it and re-insert it.
You might want to do something like here below to achieve it:
private ZipFile addFileToExistingZip(File zipFile, File versionFile) throws IOException{
// get a temp file
File tempFile = File.createTempFile(zipFile.getName(), null);
// delete it, otherwise you cannot rename your existing zip to it.
tempFile.delete();
boolean renameOk=zipFile.renameTo(tempFile);
if (!renameOk)
{
throw new RuntimeException("could not rename the file "+zipFile.getAbsolutePath()+" to "+tempFile.getAbsolutePath());
}
byte[] buf = new byte[4096 * 1024];
ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
ZipEntry entry = zin.getNextEntry();
while (entry != null) {
String name = entry.getName();
boolean toBeDeleted = false;
if (versionFile.getName().indexOf(name) != -1) {
toBeDeleted = true;
}
if(!toBeDeleted){
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(name));
// Transfer bytes from the ZIP file to the output file
int len;
while ((len = zin.read(buf)) > 0) {
out.write(buf, 0, len);
}
}
entry = zin.getNextEntry();
}
// Close the streams
zin.close();
// Compress the files
InputStream in = new FileInputStream(versionFile);
String fName = versionFile.getName();
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(fName));
// Transfer bytes from the file to the ZIP file
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
// Complete the entry
out.closeEntry();
in.close();
// Complete the ZIP file
out.close();
tempFile.delete();
return new ZipFile(zipFile);
}
The above code worked for me where the need was to add a new zip entry to an existing zip file. If the entry is already present inside the zip, then overwrite it.
Comments/improvements in the code are welcome!
Thanks!
If you try to add a duplicate ZipEntry you will get an exception. If you want to replace the current entry you need to delete it and re-insert it. I suspect the exception you get is much the same as this one.