NegativeArraySizeException while unzipping a ZipInputStream - java

I try to send some files from server to client using ZipInputStream/ZipOutputStream.
in server, everythng goes well, but in client, when I wanna unzip it, the size of the file is -1
so it fails. what should I do and why it happens?
socket = new Socket("127.0.0.1",3000);
String outDir = "C:\\here";
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
ZipInputStream zips = new ZipInputStream(bis);
ZipEntry zipEntry = null;
while(null != (zipEntry = zips.getNextEntry())){
String fileName = zipEntry.getName();
File outFile = new File(outDir + "/" + fileName);
System.out.println(outFile.getName()+" "+zipEntry.getCompressedSize());
if(zipEntry.isDirectory()){
File zipEntryFolder = new File(zipEntry.getName());
if(zipEntryFolder.exists() == false){
outFile.mkdirs();
}
continue;
}else{
File parentFolder = outFile.getParentFile();
if(parentFolder.exists() == false){
parentFolder.mkdirs();
}
}
System.out.println("ZipEntry::"+zipEntry.getCompressedSize());
FileWriter fW=new FileWriter(outFile);
try (BufferedWriter bfW = new BufferedWriter(fW)) {
bfW.write(zips.getNextEntry().toString());
}
}
socket.close();
}
the result for zipEntry.getCompressedSize(); is equal to -1. but right after writing it into socket in server, i check the size and it is the actual size. so I feel puzzled.
the exception that IDE gives is Error in Client invalid stored block lengths

You can't ever rely on getSize returning the actual uncompressed size. You need to call zips.read from the ZipInputStream until it doesn't read any more bytes.

Related

Not able to read ZipInputStream returned by ZipFile.getInputStream(ZipEntry) method

I am trying to read extract a given file from zip file. Zip file contains directories & sub-directories as well. I tried Java7 nio file apis but since my zip has subdirectories as well, I need to provide complete path to extract the file, which is not suitable in my scenario. As I have to take filetobeextracted input from user. I have been trying below code for it but somehow read method of ZipInputStream not reading any contents to buffer. On debugging I found out that ZipEntry object value is null inside ZipInputStream due to its read method simply returns -1.But now I am stuck as I am not able to figure out how that value is being set for it.
try(OutputStream out=new FileOutputStream("filetoExtract");) {
zipFile = new ZipFile("zipFile");
Enumeration<? extends ZipEntry> e = zipFile.entries();
while (e.hasMoreElements()) {
ZipEntry entry = e.nextElement();
if (!entry.isDirectory()) {
String entryName = entry.getName();
String fileName = entryName.substring(entryName.lastIndexOf("/") + 1);
System.out.println(i++ + "." + entryName);
if (searchFile.equalsIgnoreCase(fileName)) {
System.out.println("File Found");
BufferedInputStream bufferedInputStream = new BufferedInputStream(zipFile.getInputStream(entry));
ZipInputStream zin = new ZipInputStream(bufferedInputStream);
byte[] buffer = new byte[9000];
int len;
while ((len = zin.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.close();
break;
}
}
}
} catch (IOException ioe) {
System.out.println("Error opening zip file" + ioe);
}
Please advice what I am doing wrong here. Thanks
EDIT:
After debugging little more I found out that ZipFile class has inner class of similar name(ZipFileInputStream). So it was creating object of it rather than the outside ZipFileInputStream class. So I tried out below code and it worked out well. But I don't quite understand things here, what has happened. If someone could help me logic behind the scenes would be really great.
// BufferedInputStream bufferedInputStream = new
//BufferedInputStream(zipFile.getInputStream(entry));
//ZipInputStream zin = new ZipInputStream(bufferedInputStream);
InputStream zin= zipFile.getInputStream(entry);
The second line is unnecessary, as zipFile.getInputStream(entry) already returns an InputStream that represents the decompressed data. Therefore there's no need (or in fact it's wrong) to wrap that InputStream in yet another ZipInputStream:
BufferedInputStream bufferedInputStream = new BufferedInputStream(zipFile.getInputStream(entry));
ZipInputStream zin = new ZipInputStream(bufferedInputStream);

Download, decompress, and parse zip file into Java object - unable to read bytes from ZipInputStream

I have the following, which fails to print a string to console as I would expect it to:
String url = "http://mis.ercot.com/misdownload/servlets/mirDownload?
mimic_duns=000000000&doclookupId=698819309";
URL obj = new URL(url.trim());
HttpURLConnection conn = (HttpURLConnection) obj.openConnection();
conn.getResponseCode();
InputStream stream = conn.getInputStream();
ZipInputStream zis = new ZipInputStream(stream);
byte[] buffer = new byte[1024];
int i = zis.read(buffer);
String str = new String(buffer, StandardCharsets.UTF_8);
System.out.println(str);
At the URL, there is zip file, which has an XML file which I need to eventually parse, but for now I will be satisfied to simply print it to the console, and thus confirm I have succesfully unzipped the file.
Something like the following does indeed generate the correct name of the file:
ZipEntry ze = zis.getNextEntry();
System.out.println(ze);
Thus I know I am on the right track, but I do not need the name of the file, I do not even need the file, I need the XML entries, because my eventual goal is to persist to SQL.
The following loop should get you started
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
byte contents[] = new byte[4096];
int direct;
while ((direct = zis.read(contents, 0, contents.length)) >= 0) {
System.out.println(entry.getName() + ", " + direct + " bytes");
for (byte con : contents) {
System.out.print((char) con);
}
}
System.out.println();
}
Adapted from How to read file from ZIP using InputStream?

how to decode/ get encoding of file (Power BI desktop file)

I am having power BI desktop report(pbix) internal file (DataMashup), which i am trying to decode.
My Aim is to create Power-BI desktop report, Data Model using any programming language. I am using Java for initial.
files are encoded with some encoding technique.
I tried to get encoding of file and it is returning windows 1254. but decoding is not happening.
File f = new File("example.txt");
String[] charsetsToBeTested = {"UTF-8", "windows-1254", "ISO-8859-7"};
CharsetDetector cd = new CharsetDetector();
Charset charset = cd.detectCharset(f, charsetsToBeTested);
if (charset != null) {
try {
InputStreamReader reader = new InputStreamReader(new FileInputStream(f), charset);
int c = 0;
while ((c = reader.read()) != -1) {
System.out.print((char)c);
}
reader.close();
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
}catch(IOException ioe){
ioe.printStackTrace();
}
}else{
System.out.println("Unrecognized charset.");
}
Unzipping of file is also not working
public void unZipIt(String zipFile, String outputFolder)
{
byte buffer[] = new byte[1024];
try
{
File folder = new File(outputFolder);
if(!folder.exists())
{
folder.mkdir();
}
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
System.out.println(zis);
System.out.println(zis.getNextEntry());
for(ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry())
{
String fileName = ze.getName();
System.out.println(ze);
File newFile = new File((new StringBuilder(String.valueOf(outputFolder))).append(File.separator).append(fileName).toString());
System.out.println((new StringBuilder("file unzip : ")).append(newFile.getAbsoluteFile()).toString());
(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();
}
zis.closeEntry();
zis.close();
System.out.println("Done");
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
The file contains a binary header and then XML with UTF-8 specified.
The header data seems to hold the file name (Config/Package.xml), so assuming a zip format is understandable. With a zip format also there would be binary data at the end of file.
Maybe the file was downloaded using FTP, and a text conversion ("\n" to "\r\n") was done. Then the zip would be corrupted. Renaming the file to .zip might help testing the file with zip tools.
Try first the .tar format. This would be logical as the XML file is not compressed. Add .tar to the file ending.
Otherwise, if the content is always UTF-8 XML:
Path f = Paths.get("example.txt");
String start ="<?xml";
String end = ">";
byte[] bytes = Files.readAllBytes(f);
String s = new String(bytes, StandardCharsets.ISO_8859_1); // Single byte encoding.
int startI = s.indexOf(start);
int endI = s.lastIndexOf(end) + end.length();
//bytes = Arrays.copyOfRange(bytes, startI, endI);
String xml = new String(bytes, startI, endI - startI, StandardCharsets.UTF_8);
You can use the System.IO.Packaging library to extract the Power BI data mashup. It uses the OPC package standard, see here.

How to create a ZIP InputStream in Android without creating a ZIP file first?

I use NanoHTTPD as web server in my Android APP, I hope to compress some files and create a InputStream in server side, and I download the InputStream in client side using Code A.
I have read Code B at How to zip and unzip the files?, but how to create a ZIP InputStream in Android without creating a ZIP file first?
BTW, I don't think Code C is good way, because it make ZIP file first, then convert ZIP file to FileInputStream , I hope to create a ZIP InputStream directly!
Code A
private Response ActionDownloadSingleFile(InputStream fis) {
Response response = null;
response = newChunkedResponse(Response.Status.OK, "application/octet-stream",fis);
response.addHeader("Content-Disposition", "attachment; filename="+"my.zip");
return response;
}
Code B
public static void zip(String[] files, String zipFile) throws IOException {
BufferedInputStream origin = null;
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
try {
byte data[] = new byte[BUFFER_SIZE];
for (int i = 0; i < files.length; i++) {
FileInputStream fi = new FileInputStream(files[i]);
origin = new BufferedInputStream(fi, BUFFER_SIZE);
try {
ZipEntry entry = new ZipEntry(files[i].substring(files[i].lastIndexOf("/") + 1));
out.putNextEntry(entry);
int count;
while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) {
out.write(data, 0, count);
}
}
finally {
origin.close();
}
}
}
finally {
out.close();
}
}
Code C
File file= new File("my.zip");
FileInputStream fis = null;
try
{
fis = new FileInputStream(file);
} catch (FileNotFoundException ex)
{
}
ZipInputStream as per the documentation ZipInputStream
ZipInputStream is an input stream filter for reading files in the ZIP file format. Includes support for both compressed and uncompressed entries.
Earlier I answered to this question in a way that it is not possible using ZipInputStream. I am Sorry.
But after investing some time I found that it is possible as per the below code
It is very much obvious that since you are sending files in zip format
over the network.
//Create proper background thread pool. Not best but just for solution
new Thread(new Runnable() {
#Override
public void run() {
// Moves the current Thread into the background
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
HttpURLConnection httpURLConnection = null;
byte[] buffer = new byte[2048];
try {
//Your http connection
httpURLConnection = (HttpURLConnection) new URL("https://s3-ap-southeast-1.amazonaws.com/uploads-ap.hipchat.com/107225/1251522/SFSCjI8ZRB7FjV9/zvsd.zip").openConnection();
//Change below path to Environment.getExternalStorageDirectory() or something of your
// own by creating storage utils
File outputFilePath = new File ("/mnt/sdcard/Android/data/somedirectory/");
ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(httpURLConnection.getInputStream()));
ZipEntry zipEntry = zipInputStream.getNextEntry();
int readLength;
while(zipEntry != null){
File newFile = new File(outputFilePath, zipEntry.getName());
if (!zipEntry.isDirectory()) {
FileOutputStream fos = new FileOutputStream(newFile);
while ((readLength = zipInputStream.read(buffer)) > 0) {
fos.write(buffer, 0, readLength);
}
fos.close();
} else {
newFile.mkdirs();
}
Log.i("zip file path = ", newFile.getPath());
zipInputStream.closeEntry();
zipEntry = zipInputStream.getNextEntry();
}
// Close Stream and disconnect HTTP connection. Move to finally
zipInputStream.closeEntry();
zipInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
// Close Stream and disconnect HTTP connection.
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
}
}).start();

Spring: how to parse uploaded zip file?

I uploaded my zip archive to the server and want to open .txt and .jpg files in it. I successfully get my archive in my Controller and get the name of each file via ZipEntry. Now I want to open it but for this I should get a full path to my file.
I haven't found how I can do that. Could you suggest some approach how to do that ?
Update
I try to use example have been suggested below but I am not be able open the file
ZipFile zFile = new ZipFile("trainingDefaultApp.zip");
I have got the FileNotFoundException
So I return to my start point. I have upload form in Java Spring application. In controller I had got a zip archive as byte[]
#RequestMapping(method = RequestMethod.POST)
public String create(UploadItem uploadItem, BindingResult bindingResult){
try {
byte[] zip = uploadItem.getFileData().getBytes();
saveFile(zip);
Then I had got each ZipEntry
InputStream is = new ByteArrayInputStream(zip);
ZipInputStream zis = new ZipInputStream(is);
ZipEntry entry = null;
while ((entry = zis.getNextEntry()) != null) {
String entryName = entry.getName();
if (entryName.equals("readme.txt")) {
ZipFile zip = new ZipFile(entry.getName()); // here I had got an exception
According to docs I did all right but as for me it is strange to pass the file name only and suspect that you successfully will open the file
I resolve my uissue. The solution is work directly with ZipInputStream. Here the code:
private void saveFile(byte[] zip, String name, String description) throws IOException {
InputStream is = new ByteArrayInputStream(zip);
ZipInputStream zis = new ZipInputStream(is);
Application app = new Application();
ZipEntry entry = null;
while ((entry = zis.getNextEntry()) != null) {
String entryName = entry.getName();
if (entryName.equals("readme.txt")) {
new Scanner(zis); //!!!
//...
zis.closeEntry();
zipFile.getInputStream(ZipEntry entry) will return you the inputstream for the specific entry.
Check out the javadocs for ZipFile.getInputStream() - http://docs.oracle.com/javase/6/docs/api/java/util/zip/ZipFile.html#getInputStream(java.util.zip.ZipEntry).
Update:
I misread your question. For using the ZipInputStream, there is sample code on Oracle's website (http://java.sun.com/developer/technicalArticles/Programming/compression/) that shows you how to read from the stream. See the first code sample: Code
Sample 1: UnZip.java.
Copying here, it is reading from the entry and writing it directly to a file, but you could replace that with whatever logic you need:
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry;
while((entry = zis.getNextEntry()) != null) {
System.out.println("Extracting: " +entry);
int count;
byte data[] = new byte[BUFFER];
// write the files to the disk
FileOutputStream fos = new FileOutputStream(entry.getName());
dest = new
BufferedOutputStream(fos, BUFFER);
while ((count = zis.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
}
}

Categories

Resources