ByteArrayOutputStream.toString() generating extra characters - java

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)

Related

Java - downloading image by bytes downloads a broken image

Hello I was curious on how data can be downloaded in java, so I looked through few methods and decided to use BufferedInputStream.
Now when I download, I download the file by 1024 bytes burst, and everytime it downloads 1kb I concat the temp array to the main data array.tH
I use this concat method:
public static byte[] concat(byte[] data, byte[] bytes) {
byte[] result = Arrays.copyOf(data, data.length + bytes.length);
System.arraycopy(bytes, 0, result, data.length, bytes.length);
return result;
}
This is my download process:
URL target = new URL ("http://freshhdwall.com/wp-content/uploads/2014/08/Image-Art-Gallery.jpg");
URLConnection t = target.openConnection();
t.setRequestProperty("User-Agent", "NING/1.0");
t.connect();
BufferedInputStream stream = new BufferedInputStream(t.getInputStream());
final byte[] bytes = new byte[1024];
int count;
byte[] data = new byte[0];
while ( (count = stream.read(bytes, 0, bytes.length)) != -1) {
System.out.println(count);
data = concat(data, bytes);
}
Now after downloading, I convert the bytes array to BufferedImage using ByteArrayInputStream:
InputStream s = new ByteArrayInputStream(data);
BufferedImage m = ImageIO.read(s);
And then I display the result:
JFrame j = new JFrame();
j.add(new JLabel(new ImageIcon(m)));
j.pack();
j.setVisible(true);
Now the result image looks like this:
(source: gyazo.com)
As you see, the image looks broken, missing bytes when downloading.
This is the real image:
img http://freshhdwall.com/wp-content/uploads/2014/08/Image-Art-Gallery.jpg
What did I do wrong that it displays the image like that?
On each loop iteration, you potentially read less than bytes.length bytes. As such, you can't use the full length of the array. You need to use exactly that part that was actually read.
One solution is to use
while ((count = stream.read(bytes, 0, bytes.length)) != -1) {
System.out.println(count); // this should hint at this
data = concat(data, bytes, count); // use the count
}
and
public static byte[] concat(byte[] data, byte[] bytes, int count) {
byte[] result = Arrays.copyOf(data, data.length + count);
System.arraycopy(bytes, 0, result, data.length, count);
return result;
}
so as to only copy over the bytes you've actually received.
Consider using some of the solutions here. They are probably more efficient or, at least, more readable.

Java: Error creating a GZIPInputStream: Not in GZIP format

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.

Create a ArrayList of byte Array in Android

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() );

Java: Is there a way to get the expected uncompressed length of a zipped byte array?

I'm using java.util.zip to compress and uncompress byte arrays, using Inflater and Deflater.
Does the compressed result contain information about the expected length of the original data or do I have to store it myself?
I would like to know the expected length of the uncompressed information without uncompressing all of the data.
If you just compress and decompress byte arrays - without storing them in a ZipEntry - you must save the size yourself, as the byte array to which you compress the data is not necessarily used to its full extent.
You can see this clearly from the example in Deflater's javadoc:
try {
// Encode a String into bytes
String inputString = "blahblahblah??";
byte[] input = inputString.getBytes("UTF-8");
// Compress the bytes
byte[] output = new byte[100];
Deflater compresser = new Deflater();
compresser.setInput(input);
compresser.finish();
int compressedDataLength = compresser.deflate(output);
// Decompress the bytes
Inflater decompresser = new Inflater();
decompresser.setInput(output, 0, compressedDataLength);
byte[] result = new byte[100];
int resultLength = decompresser.inflate(result);
decompresser.end();
// Decode the bytes into a String
String outputString = new String(result, 0, resultLength, "UTF-8");
} catch(java.io.UnsupportedEncodingException ex) {
// handle
} catch (java.util.zip.DataFormatException ex) {
// handle
}
The code must maintain the compressed data's lenght as the output array is of length 100, no matter the actual length of the data it stores.

FileInputStream to byte array in Android application

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.

Categories