I am trying to use the following Java code to compress and uncompress a String. But the line that creates a new GZipInputStream object out of a new ByteArrayInputStream object throws a "java.util.zip.ZipException: Not in GZIP format" exception. Does anyone know how to solve this?
String orig = ".............";
// compress it
ByteArrayOutputStream baostream = new ByteArrayOutputStream();
OutputStream outStream = new GZIPOutputStream(baostream);
outStream.write(orig.getBytes());
outStream.close();
String compressedStr = baostream.toString();
// uncompress it
InputStream inStream = new GZIPInputStream(new ByteArrayInputStream(compressedStr.getBytes()));
ByteArrayOutputStream baoStream2 = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int len;
while((len = inStream.read(buffer))>0)
baoStream2.write(buffer, 0, len);
String uncompressedStr = baoStream2.toString();
Mixing String and byte[]; that does never fit. And only works on the the same OS with same encoding. Not every byte[] can be converted to a String, and the conversion back could give other bytes.
The compressedBytes need not represent a String.
Explicitly set the encoding in getBytes and new String.
String orig = ".............";
// Compress it
ByteArrayOutputStream baostream = new ByteArrayOutputStream();
OutputStream outStream = new GZIPOutputStream(baostream);
outStream.write(orig.getBytes("UTF-8"));
outStream.close();
byte[] compressedBytes = baostream.toByteArray(); // toString not always possible
// Uncompress it
InputStream inStream = new GZIPInputStream(
new ByteArrayInputStream(compressedBytes));
ByteArrayOutputStream baoStream2 = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int len;
while ((len = inStream.read(buffer)) > 0) {
baoStream2.write(buffer, 0, len);
}
String uncompressedStr = baoStream2.toString("UTF-8");
System.out.println("orig: " + orig);
System.out.println("unc: " + uncompressedStr);
Joop seems to have the solution up there, but I feel I must add this:
Compression in general, and GZIP in particular will produce a binary stream.
You MUST not try to construct a String from this stream - it WILL break.
If you need to take it to a plain text representation, look into Base64 encoding, hex encoding, heck, even simple binary encoding.
In short, String objects are for things that humans read. Byte arrays (and many other things) are for things machines read.
You encoded baostream to a string with your default platform encoding, probably UTF-8. You should be using baostream.getBytes() to work with binary data, not strings.
If you insist on a string, use an 8-bit encoding, e.h. baostream.toString("ISO-8859-1"), and read it back with the same charset.
Related
What is the efficient way to encode and decode an audio file in android
I have tried the Base64 as below but after decoding the file size get increased.
Encode
ByteArrayOutputStream objByteArrayOS = new ByteArrayOutputStream();
File file = new File(path);
FileInputStream objFileIS;
try {
objFileIS = new FileInputStream(file);
byte[] byteBufferString = new byte[1024];
for (int readNum; (readNum = objFileIS.read(byteBufferString)) != -1;) {
objByteArrayOS.write(byteBufferString, 0, readNum);
System.out.println("read " + readNum + " bytes,");
byte[] bytes = FileUtils.readFileToByteArray(file);
strAttachmentCoded = Base64.encodeToString(bytes,
Base64.DEFAULT);
Decode
byte[] decoded = Base64.decode(strAttachmentCoded,
Base64.DEFAULT);
// byte[] decoded1 = Base64.decode(byteBinaryData1, 0);
File file1 = new File(pathAudio);
FileOutputStream os = new FileOutputStream(file1, true);
os.write(decoded);
os.close();
i want audio in String format to send to server and retrieve the same as per the user requirement.
wikipedia:base64 (rfc3548) is the right method to choose I would think. It is most common now I think having taken over from wikipedia:uuencoding.
To answer the question . . .
You could add some padding. The wikipedia article on base64 gives a good example of padding.
Or you could add a header to your audio string including length. The header could also include other control data so it may be something you want to include anyway.
I have the following code:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int size = 4096;
byte[] bytes = new byte[size];
while (is.read(bytes, 0, size) != -1)
{
baos.write(bytes);
baos.flush();
}
When I do:
String s = baos.toString();
I get \u0000-s appended to my string. So, if my character data is only X bytes out of Y, the Y-Z will get prefilled with \u0000 making it impossible to check for equals. What am I doing wrong here? How should I be converting the bytes to a String in this case?
The entire array (all 4096 bytes) is be written to the output - arrays have no idea of how much "useful data" they contain!
Store how much was read into a variable (InputStream.read returns a useful number) and specify that to the appropriate OutputStream.write overload to only write a portion (that which contains the useful data) of the array.
While the above change should "fix" the problem, it is generally recommended to use the string<->byte[] conversion forms that take in an explicit character set.
You should only be writing as much data as you are reading in each time through the loop:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int size;
byte[] bytes = new byte[4096];
while (size = is.read(bytes, 0, bytes.length) != -1)
{
baos.write(bytes, 0, size);
}
baos.flush();
String s = baos.toString();
You might consider specifying a specific character set for converting the bytes to a String. The no-arg toString() method uses the platform default encoding.
new String(baos.toByteArray(), 0, strLen, encoding)
I want to read bytes from httpresponse coming from server continuosly into an array.
I'm creating a byte array with a maximum size of 2048.
So, I wanted to create a dynamically increasing array and I found that ArrayList is the solution.
How can i overcome this solution?
Any help would be appreciated lot
You can use a ByteArrayOutputStream to accumulate the bytes as you read them from the server. I would not use an ArrayList<Byte> because it requires boxing every byte value in a Byte.
When you want to access the bytes that have been accumulated, just call toByteArray() on the ByteArrayOutputStream.
You can have an array of byte like:
List<Byte> arrays = new ArrayList<Byte>();
To convert it back to arrays
Byte[] soundBytes = arrays.toArray(new Byte[arrays.size()]);
- You can also use ByteArrayInputStream and ByteArrayOutputStream.
Eg:
InputStream inputStream = socket.getInputStream();
// read from the stream
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] content = new byte[ 2048 ];
int bytesRead = -1;
while( ( bytesRead = inputStream.read( content ) ) != -1 ) {
baos.write( content, 0, bytesRead );
} // while
// now, as you have baos in hand, I don't think you still need a bais instance
// but, to make it complete,
// now you can generate byte array input stream as below
ByteArrayInputStream bais = new ByteArrayInputStream( baos.toByteArray() );
I am using the code provided by this accepted answer to send a list of files over a socket in Java. My goal is to be receiving a list of images. What I would like to do is read these images directly into memory as BufferedImages before writing them to disk. However, my first attempts, which was to use ImageIO.read(bis) (again, see the attached question) failed, as it attempted to continue reading beyond the end of the first image file.
My current idea is to write the data from the socket to a new output stream, then read that stream from an intput stream that is passed to ImageIO.read(). This way, I can write it byte by byte as the program is currently doing, but send it to the BufferedImage rather than the file. however I'm not sure how to link the output stream to an input stream.
Can anyone recommend simple edits to the code above, or provide another method of doing this?
In order to read the image before writing it to disk, you'll need to use a ByteArrayInputStream. http://docs.oracle.com/javase/6/docs/api/java/io/ByteArrayInputStream.html
Basically, it creates a inputstream that reads from a specified byte array. So, you'd read the image length, then it's name, then the length-amount of bytes, create the ByteArrayInputStream, and pass it to ImageIO.read
Example snippet:
long fileLength = dis.readLong();
String fileName = dis.readUTF();
byte[] bytes = new byte[fileLength];
dis.readFully(bytes);
BufferedImage bimage = ImageIO.read(new ByteArrayInputStream(bytes));
Or using the code from the other answer you cited:
String dirPath = ...;
ServerSocket serverSocket = ...;
Socket socket = serverSocket.accept();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
DataInputStream dis = new DataInputStream(bis);
int filesCount = dis.readInt();
File[] files = new File[filesCount];
for(int i = 0; i < filesCount; i++)
{
long fileLength = dis.readLong();
String fileName = dis.readUTF();
byte[] bytes = new byte[fileLength];
dis.readFully(bytes);
BufferedImage bimage = ImageIO.read(new ByteArrayInputStream(bytes));
//do some shit with your bufferedimage or whatever
files[i] = new File(dirPath + "/" + fileName);
FileOutputStream fos = new FileOutputStream(files[i]);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write(bytes, 0, fileLength);
bos.close();
}
dis.close();
I have a FileInputStream created using Context.openFileInput(). I now want to convert the file into a byte array.
Unfortunately, I can't determine the size of the byte array required for FileInputStream.read(byte[]). The available() method doesn't work, and I can't create a File to check it's length using the specific pathname, probably because the path is inaccessible to non-root users.
I read about ByteArrayOutputStream, and it seems to dynamically adjust the byte array size to fit, but I can't get how to read from the FileInputStream to write to the ByteArrayOutputStream.
This should work.
InputStream is = Context.openFileInput(someFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
while ((int bytesRead = is.read(b)) != -1) {
bos.write(b, 0, bytesRead);
}
byte[] bytes = bos.toByteArray();
This is the easiest way
FileInputStream fis = openFileInput(fileName);
byte[] buffer = new byte[(int) fis.getChannel().size()];
fis.read(buffer);
You can pre-allocate the byte array using
int size = context.getFileStreamPath(filename).length();
This way, you will avoid allocating memory chunks every time your ByteArrayOutputStream fills up.
For the method to work on any device and aplication you just need to replace:
InputStream is = Context.getContentResolver().openInputStream(yourFileURi);
This way you can encode external files as well.