I'm writing a Java applet that need to read some XML and image files inside a ZIP file. The Zip file will be download through HTTP and the applet is unsigned, so I need to use java.util.zip.ZipInputStream to manipulated the data. There's a problem when I'm trying to read a PNG file inside the Zip file.
The steps I handle the Zip file:
Download the Zip through Http
URL resourceURL = new URL(source);
HttpURLConnection httpConnection= (HttpURLConnection) resourceURL.openConnection();
httpConnection.connect();
InputStream resourceFileIn = httpConnection.getInputStream();
Use ZipInputStream to hold the data downloaded
ZipInputStream resourceZipIn = new ZipInputStream(resourceFileIn);
Iterate through every ZipEntry and extract the corresponding byte array
ArrayList<ExtractedEntry> extractedList = new ArrayList<ExtractedEntry>();
ZipEntry currentEntry;
while ((currentEntry = resourceZipIn.getNextEntry()) != null) {
byte[] byteHolder = new byte[(int) currentEntry.getSize()];
resourceZipIn.read(byteHolder, 0, byteHolder.length);
extractedList.add(new ExtractedEntry(currentEntry.getName(), byteHolder));
}
remarks: every ZipEntry extracted is hold by the following class
public class ExtractedEntry {
private String name;
private byte[] byteArray;
public ExtractedEntry(String name, byte[] byteArray) {
super();
this.name = name;
this.byteArray = byteArray;
}
public String getName() {
return name;
}
public byte[] getByteArray() {
return byteArray;
}
}
Find the file I want to read from in the extracted list
ExtractedEntry bgEntry = null;
for (int j = 0; j < extractedList.size() && bgEntry == null; j++) {
if (extractedList.get(j).getName().equals("background.png")) {
bgEntry = extractedList.get(j);
}
}
Perform specific action according to need
InputStream mapBgIn = new ByteArrayInputStream(bgEntry.getByteArray());
BufferedImage bgEntry = ImageIO.read(bgIn);
I list out only the action of reading the PNG file as that is where I encounter the problem. When I try to read the image in the way mentioned above, I always receive the following error at the last line of step 5.
javax.imageio.IIOException: Error reading PNG image data at com.sun.imageio.plugins.png.PNGImageReader.readImage(Unknown Source)
at com.sun.imageio.plugins.png.PNGImageReader.read(Unknown Source)
at javax.imageio.ImageIO.read(Unknown Source)
at javax.imageio.ImageIO.read(Unknown Source)
at com.quadd.soft.game.wtd.lib.resource.ResourceManager.loadHttpZipRes(ResourceManager.java:685)
Caused by: javax.imageio.IIOException: Unknown row filter type (= 7)!
at com.sun.imageio.plugins.png.PNGImageReader.decodePass(Unknown Source)
at com.sun.imageio.plugins.png.PNGImageReader.decodeImage(Unknown Source)
... 29 more
However, if I read the image in the following way starting from step 3, there's no problem.
ZipInputStream resourceZipIn = new ZipInputStream(resourceFileIn);
ZipEntry testEntry;
while ((testEntry = resourceZipIn.getNextEntry()) != null) {
if (testEntry.getName().equals("background.png")) {
BufferedImage bgEntry = ImageIO.read(resourceZipIn);
}
}
Therefore, I guess that there's some problem with my code at extracting the bytes from java.util.zip.ZipInputStream and put it back for reading the image. But I'm quite new to manipulating stream so I just couldn't figure out what exactly is the problem. I would like to ask if anyone could point out what mistake I've made in the code which cause the error.
The read method does not guarantee that it fills the byte array; it reads only a small block and returns the number of bytes that it read. You need a loop, or use a helper class that does fill the array.
For example
DataInputStream in = new DataInputStream(resourceZipIn);
in.readFully(byteHolder);
in.close();
Related
public class GzExtractor implements Extractor {
Logger logger = LoggerFactory.getLogger(GzExtractor.class);
private static final int BUFFER_SIZE = 1024;
byte[] buff = new byte[BUFFER_SIZE];
private File file;
private String destinationPath;
public GzExtractor(File file, String destinationPath) {
this.file = file;
this.destinationPath = destinationPath;
}
public void extract() {
try {
File destDir = new File(destinationPath);
if (!destDir.exists()) {
destDir.mkdir();
}
GZIPInputStream gZipObj = new GZIPInputStream(new FileInputStream(file));
String extractedFilename = file.getName().split(".gz")[0];
OutputStream fosObj = new FileOutputStream(destinationPath + extractedFilename);
int len;
while ((len = gZipObj.read(buff)) > 0) {
fosObj.write(buff, 0, len);
}
gZipObj.close();
fosObj.close();
} catch (Exception e) {
logger.info("GZ Exception : {}",e.getMessage());
}
}
}
I'm getting the error of unexpected ZLIB stream but the file is extracted successfully.
I tried some solutions but none of them solved this. I tried closing the gzip stream before reading as I found that from one of the answers here. But that throws another error of course.
I am confused why I'm getting this and I want to basically eliminate the error statement.
[pool-1-thread-1] INFO service.ExtractorImpl.GzExtractor - GZ Exception : Unexpected end of ZLIB input stream
Okay so probably the compressed file was not in the correct format. I was using an FTP server where I was uploading different kinds of files i.e zip, gzip, CSV, etc. It was in my logic that the decompression would occur on the file according to the compression type of the file. While downloading from my FTP server, I forgot to mention the type of file that must be binary to include zip files.
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
So the file which was being decompressed must not be in a correct format. Maybe that is why I was getting this error.
After setting the file type to this, it worked okay.
This question already has answers here:
Java - Read file and split into multiple files
(11 answers)
Closed 3 years ago.
How can I split a file into parts larger than 2GB?
An array of bytes accepts an int instead of a long as the size. any solution?
public void splitFile(SplitFile file) throws IOException {
int partCounter = 1;
int sizeOfFiles = (int)value;
byte[] buffer = new byte[sizeOfFiles];
File f = file.getFile();
String fileName = f.getName();
try (FileInputStream fis = new FileInputStream(f);
BufferedInputStream bis = new BufferedInputStream(fis)) {
int bytesAmount = 0;
while ((bytesAmount = bis.read(buffer)) > 0) {
String filePartName = fileName + partCounter + file.config.options.getExtension();
partCounter++;
File newFile = new File(f.getParent(), filePartName);
try (FileOutputStream out = new FileOutputStream(newFile)) {
out.write(buffer, 0, bytesAmount);
}
}
}
}
Don't read the entire file into memory, obviously, or even an entire 'part file'.
Your code as pasted will split the file into as many parts as the read method partitions; this seems very silly; after all, the read() method is specced to allow it to partition into single byte increments.
Don't make a new part-file for every call to read. Instead, separate this out: Your read call gets anywhere from 1 to <BUFFER_SIZE> bytes, and your part's size is <PART_SIZE> large; these two things do not have to be the same and you shouldn't write the code that way.
Once you have an open FileOutputStream you can call .write(buffer, 0, bytesAmount) on it any number of times; you can even call .write(buffer, 0, theSmallerOfBytesLeftToWriteInThisPartAndBytesAmount) followed by opening up the next part file FileOutputStream and calling .write(buffer, whereWeLeftOff, remainder) on that one.
I have a simple code to extract zip files, it was working just fine as expected but during my test I tried my code with some zip files (fonts, icons and templates I downloaded from internet) just to make sure it should extract any zip files provided, but its not working with some zip files, here is the minimized code to regenerate this issue:
package com.test.mytest;
import java.io.FileInputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
public class ZipExtractTest {
public static final String ZIP_FILE = "/Users/XXXXX/Downloads/janne.zip";
public static void main(String[]args) {
unzipFile(ZIP_FILE);
unzipStream(ZIP_FILE);
}
public static void unzipFile(String zipName) {
try {
ZipFile zf = new ZipFile(zipName);
Enumeration ent = zf.entries();
while(ent.hasMoreElements()) {
System.out.println(ent.nextElement());
}
} catch(Exception e) {
System.out.println(e);
}
}
public static void unzipStream(String zipName) {
try {
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipName));
ZipEntry ze = zis.getNextEntry();
if(ze == null) {
System.out.println("unable to get first entry from zip file");
zis.close();
return;
}
while(ze != null) {
System.out.println("Entry Found: " + ze);
ze = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
} catch(Exception e) {
System.out.println(e);
}
}
}
actually In my real application i have to extract zip files through inputstreams. In the code above I am trying to extract "janne.zip" I downloaded this file from http://www.iconian.com/fonts/janne.zip I am able to extract it using any zip-tool and surprisingly through "unzipFile(String zipName)" method as well, but with unzipStream(String zipName) method
ZipEntry ze = zis.getNextEntry();
returns null
any help would be appreciated
Not an answer as to why this particular file doesn't work with java.util.zip, but if you have the option to replace your use of java.util.zip.ZipInputStream with the Apache commons-compress org.apache.commons.compress.archivers.zip.ZipArchiveInputStream (which should be API-compatible) then I've just tested that on your example file and it seems to work successfully.
Generally I find commons-compress to be much more reliable than java.util.zip at unpacking files created by tools other than the java.util.zip classes themselves.
Edit: I've done a bit of debugging in Eclipse and it looks like this particular zip file has a single segment spanning marker of 0x30304b50 before the LOC signature (0x04034b50) of the first entry's local header. This is something that commons-compress knows how to handle but java.util.zip doesn't - if j.u.z.ZipInputStream sees anything other than a LOC signature then getNextEntry() will return null.
Funny!
I debugged your code and got the same error. I found an header check in the ZipInputStream implementation, but not in the ZipFile implementation.
Dont ask me why, but the header in your zip file is not valid!
Your file is starting with: 50 4B 30 30 50 4B 03 04
A valid Zip File Header is: 50 4B 03 04
If you delete the first bytes (50 4B 30 30) from your file you got a valid header an you can read you file!
I was having the same problem ! Lucky for me I was able to resolve it.
first i reset the blob data in the database then used java code to zip it using ZipInputStream. Although I am not sure, the null ZipEntry problem could be because of 2 things:
1. The blob data in the database is not stored correctly (or may be its already compressed, some databases compress blob data at the time of storage. you can google this too).
2. The input/output streams can also cause trouble, see this
Here is detailed description of what I did:
1. reset the blob field in database using EMPTY_BLOB and commit changes
2. used the below java program to update the blob field with a .xls file
DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver ()); // register driver
Connection conn =
DriverManager.getConnection ("jdbc:oracle:thin:#my-local-database:1521:test", "test1", "test1");
// It's faster when auto commit is off:
conn.setAutoCommit (false);
try
{
PreparedStatement pstmt = conn.prepareStatement("update content set file_content = ? where CONTENT_ID=2006");
File blob = new File("C:/Users/ankur/Desktop/Book1.xls");
FileInputStream in = new FileInputStream(blob);
pstmt.setBinaryStream(1, in);
pstmt.executeUpdate();
conn.commit();
conn.close();
System.out.println("file updated");
}
catch (SQLException e)
{
e.printStackTrace();
}
Please note that the above code will work but it absolutely does not demonstrate coding standards and practices.
3. Used the below zip method to compress data
public byte[] zipByteArray(String primaryKey, byte[] input) throws IOException{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
ZipEntry entry = new ZipEntry(primaryKey);
entry.setSize(input.length);
zos.putNextEntry(entry);
zos.write(input);
zos.closeEntry();
zos.close();
return baos.toByteArray();
}
The above method takes a byte array, zips it, puts it into a ByteArrayOutputStream. You can choose to use the ByteArrayOutputStream itself, due to some requirements I am converting it to byte array.
4. I then insert the above byte array in blob field using prepared statement
5. If I use the unzip code given below, it works fine!
public byte[] unzipInputStream(InputStream is) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = null;
ZipInputStream zipIs = new ZipInputStream(new BufferedInputStream(is));
byteArrayOutputStream = new ByteArrayOutputStream();
ZipEntry entry = zipIs.getNextEntry();
while (entry != null) {
byte[] tmp = new byte[2048];
BufferedOutputStream bos = null;
bos = new BufferedOutputStream(byteArrayOutputStream);
int size = 0;
while ((size = zipIs.read(tmp)) != -1) {
bos.write(tmp, 0, size);
}
bos.flush();
bos.close();
entry = zipIs.getNextEntry();
}
zipIs.close();
return byteArrayOutputStream.toByteArray();
The output of the above method is the unzipped data.
This is my case: I'm using a library for reading files from a respository (I can't modify that library), the library has a method getContent that returns a String (it uses BasicResponseHandler to convert the response to String), but the repository also contains binary files too, and I need bytes[] to save that as a file. I tried using
content.getBytes("UTF-8") and it works with text files, but with other files like images, I get a corrupted file.
BasicResponseHandler uses this to convert the input to String (charset is UTF-8):
Reader reader = new InputStreamReader(instream, charset);
CharArrayBuffer buffer = new CharArrayBuffer(i);
try {
char[] tmp = new char[1024];
int l;
while((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
} finally {
reader.close();
}
return buffer.toString();
Does anyone know what I can do?
When you read an image, that isn't a String, and shouldn't be converted. Simply write the byte[]'s back out to file, and you'll have an image stored in said file.
If you aren't able to edit the library code being used, I would suggest looking for a new library to use. Perhaps one that doesn't assume anything about the file content type.
This question already has answers here:
Convert audio stream to WAV byte array in Java without temp file
(5 answers)
Closed 9 years ago.
After extensive research into the subject I have reached a brick wall.
All I want to do is add a collection of .wav files into a byte array, one after another, and output them all into one complete newly created .wav file. I extract all the .wav data into a byte array, skipping the .wav header and going straight for the data, then when it comes to writing it to the newly created .wav file I get an error like:
Error1: javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input stream
Error2: could not get audio input stream from input stream
The code is:
try
{
String path = "*********";
String path2 = path + "newFile.wav";
File filePath = new File(path);
File NewfilePath = new File(path2);
String [] folderContent = filePath.list();
int FileSize = 0;
for(int i = 0; i < folderContent.length; i++)
{
RandomAccessFile raf = new RandomAccessFile(path + folderContent[i], "r");
FileSize = FileSize + (int)raf.length();
}
byte[] FileBytes = new byte[FileSize];
for(int i = 0; i < folderContent.length; i++)
{
RandomAccessFile raf = new RandomAccessFile(path + folderContent[i], "r");
raf.skipBytes(44);
raf.read(FileBytes);
raf.close();
}
boolean success = NewfilePath.createNewFile();
InputStream byteArray = new ByteArrayInputStream(FileBytes);
AudioInputStream ais = AudioSystem.getAudioInputStream(byteArray);
AudioSystem.write(ais, Type.WAVE, NewfilePath);
}
Your byte array doesn't contain any header information which probably means that AutoSystem.write doesn't think it is really WAV data.
Can you create suitable header for your combined data?
Update: This question might hold the answer for you.