I am trying to serialize an object into a ZipEntry using an ObjectOutputStream, however it doesn't appear to be writing anything because when I print the byte array produced, it shows null. I tried writing a string with the ZipOutputStream, and upon printing the resulting byte array got a sizeable result. SO my question is: why is the objectoutput stream not correctly writing into the ZipEntry. (ConfigEntry does implement Serializable).
String s = "Tired, Exhausted";
ConfigEntry con = new ConfigEntry("rand", "random", 3);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ZipOutputStream zos = new ZipOutputStream(baos);
ZipEntry entry = new ZipEntry("test.txt");
ObjectOutputStream obs = new ObjectOutputStream(zos);
zos.putNextEntry(entry);
obs.writeObject(con);
obs.close();
zos.closeEntry();
zos.close();
} catch(IOException ioe) {
ioe.printStackTrace();
}
os = bs.getOutputStream();
byte[] result = baos.toByteArray();
String test = new String(result, "UTF-8");
Log.v("Mac Address", test);
Log.v("Mac Address", Arrays.toString(result));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
This baos goes out of scope after the try block. You are writing to one baos and you are looking into another baos declared in an outer scope, probably an instance member of the class.
Related
I am trying to compress and array of bytes into another array of bytes using GZIPOutputStream (in Java).
This is my code:
#Test
public void testCompressBytes() throws IOException {
final byte[] uncompressed = RandomStringUtils.randomAlphanumeric(100000 /* 100 kb */).getBytes();
// compress
byte[] compressed;
try (InputStream is = new ByteArrayInputStream(uncompressed);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream os = new GZIPOutputStream(baos)) {
IOUtils.copy(is, os); // org.apache.commons.io
os.flush();
compressed = baos.toByteArray();
}
System.out.println("Size before compression = " + uncompressed.length + ", after = " + compressed.length);
// decompress back
byte[] decompressedBack;
try (InputStream is = new GZIPInputStream(new ByteArrayInputStream(compressed));
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
IOUtils.copy(is, baos); // EXCEPTION THROWN HERE
baos.flush();
decompressedBack = baos.toByteArray();
}
assertArrayEquals(uncompressed, decompressedBack);
}
And this is the output I'm getting:
Size before compression = 100000, after = 63920
java.io.EOFException: Unexpected end of ZLIB input stream
What could I be doing wrong?
You need to call GZIPOutputStream::close before calling ByteArrayOutputStream::toByteArray, so that GZIPOutputStream writes all the end bits.
In your current code you are calling ByteArrayOutputStream::toByteArray before GZIPOutputStream::close (via try-with-resources) that's why it doesn't work.
Thanks, everybody!
Although calling GZIPOutputStream::finish() before ByteArrayOutputStream::toByteArray() seems to do the trick, I believe it's better to completely close the GZIP stream first, which in turn forces us to keep ByteArrayOutputStream outside the try-with-resources clause.
So, my reworked compression part looks like that now:
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (InputStream is = new ByteArrayInputStream(uncompressed);
GZIPOutputStream gzos = new GZIPOutputStream(baos)) {
IOUtils.copy(is, gzos);
} catch (final IOException e) {
throw new RuntimeException(e);
}
IOUtils.closeQuietly(baos);
final byte[] compressed = baos.toByteArray();
Ultimately the goal is just to zip a string and have that as a string in java
public void zip() {
try {
String myTestString = "a zip file test and another test";
InputStream in = new ByteArrayInputStream(myTestString.getBytes());
OutputStream out = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(out);
ZipEntry zipEntry = new ZipEntry("wtf.txt");
zipOut.putNextEntry(zipEntry);
zipOut.write(myTestString.getBytes(),0,myTestString.getBytes().length);
zipOut.close();
myTestString = out.toString();
out.close();
System.out.println(myTestString);
// just a test if I can read the file
in = new ByteArrayInputStream(myTestString.getBytes());
out = new FileOutputStream("c:\\t\\string.zip");
byte[] allBytes = new byte[(int) myTestString.getBytes().length];
in.read(allBytes);
out.write(allBytes);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
I have found I can write a string to a zipfile using
public void zipStringToFile2() {
try {
FileOutputStream fos = new FileOutputStream("c:/t/compressed.zip");
ZipOutputStream zipOut = new ZipOutputStream(fos);
String myTestString = "a zip file test and another test";
int buffer = myTestString.getBytes().length;
// byte[] myBytes = myTestString.getBytes();
ByteArrayOutputStream out = new ByteArrayOutputStream(buffer);
ZipEntry zipEntry = new ZipEntry("wtf.txt");
zipOut.putNextEntry(zipEntry);
zipOut.write(myTestString.getBytes(),0,buffer);
zipOut.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
but I cannot get the output of zipOut to write to a string and then have the string write to a file and then via the OS open the zipfile. How can that be done?
myTestString = out.toString();
This doesn't do what you want. bytes aren't strings. toString() doesn't give useful information (it is a debugging tool). Keep the byte array (.toByteArray()).
out.close();
close the stream after you retrieved the data? Don't do that. Close first. (not that it matters, here. ByteArrayXStream's close() doesn't do anything at all. The point is, it either does nothing in which case you should remove it, or if it does have an effect, your code would be broken).
myTestString.getBytes()
No, don't ever call that method. It gives you the bytes by decoding the characters into bytes using 'platform default encoding'. Who knows what that is.
} catch (IOException e) {
e.printStackTrace();
}
The correct 'I dunno' exception handler is throw new RuntimeException("unhandled", e);, not e.printStackTrace();. You get more info, and you get fewer WTFs (because yours will continue execution even though things are clearly wrong, which is a very bad idea).
but I cannot get the output of zipOut to write to a string
Yup. Strings aren't bytes, what you want is not possible at all. In any language. Some languages make it look like you can - those are bad languages, that conflate strings and byte arrays. Python decided to crash and burn and invent a whole new python (python2k -> python3k) to try to fix this, which goes to show. Boy that was a ton of pain and they suffered it to fix this oversight.
but I cannot get the output of zipOut to write to a string and then have the string write to a file and then via the OS open the zipfile. How can that be done?
So, replace all occurences of 'string' in that sentence with 'byte array' and all is peachy fine!
this is really what I was looking for:
public void zip() {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(baos);
ByteArrayInputStream bais = new ByteArrayInputStream(testString.getBytes());
System.out.println("testString " + testString + " testString.getBytes() " + testString.getBytes());
ZipEntry zipEntry = new ZipEntry("Results.xml");
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while((length = bais.read(bytes)) >= 0 ) {
zipOut.write(bytes, 0, length);
}
zipOut.close();
bais.close();
baos.close();
byte[] zipBytes = baos.toByteArray();
// just a test to see if can be opened in the operating system
OutputStream os = new FileOutputStream(new File("c:/t/again.zip"));
os.write(zipBytes);
os.close();
} catch(IOException e) {
e.printStackTrace();
}
}
This is how I create a simple zip archive with 3 files
FileOutputStream fos = new FileOutputStream(new File("out.zip"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (int i = 0; i < 3; i++) {
String s = "hello world " + i;
ZipEntry entry = new ZipEntry("text" + i + ".txt");
zos.putNextEntry(entry);
zos.write(s.getBytes());
zos.closeEntry();
}
}
baos.writeTo(fos);
How can I put a zip inside zip recursively in one turn on the fly? Is there any way to put ZipOutputStream or ZipEntry inside each other?
EDIT:
Solution as Mark suggested:
FileOutputStream fos = new FileOutputStream(new File("out.zip"));
ByteArrayOutputStream resultBytes = new ByteArrayOutputStream();
ByteArrayOutputStream zipOutStream = new ByteArrayOutputStream();
try (ZipOutputStream zos2 = new ZipOutputStream(zipOutStream)) {
String s = "hello world ";
ZipEntry entry = new ZipEntry("text.txt");
zos2.putNextEntry(entry);
zos2.write(s.getBytes());
zos2.closeEntry();
zos2.close();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
ZipEntry entry = new ZipEntry("text.zip");
zos.putNextEntry(entry);
zos.write(zipOutStream.toByteArray());
zos.closeEntry();
}
baos.writeTo(resultBytes);
resultBytes.writeTo(fos);
I tried to follow the solution using the 'ByteArrayOutputStream' but only manage to create corrupted zip files this way.
I ended up creating a nested ZipOutputStream directly like this:
try (FileOutputStream fos = new FileOutputStream(myZipFile); ZipOutputStream zos = new ZipOutputStream(fos)) {
ZipEntry entry = new ZipEntry("inner.zip");
zos.putNextEntry(entry);
ZipOutputStream nestedZos = new ZipOutputStream(zos);
// write stuff to nestedZos
nestedZos.finish();
zos.closeEntry();
}
The resulting zip file contains the nested structure and is valid.
For the "inner" .ZIP file, you could use a ByteArrayOutputStream instead of a FileOutputStream; then that zip will be built as data in RAM; so you can use the resulting byte array as the data for a ZipEntry in the outer .ZIP file.
Is there any way to write DataOutputStream content to an Array or a String regardless which type of data it contains?
DataOutputStream output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(String dataPath)));
Thanks
Use ByteArrrayOutputStream.
https://docs.oracle.com/javase/7/docs/api/java/io/ByteArrayOutputStream.html
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream os = new DataOutputStream(baos);
os.write(...);
byte[] data = baos.toByteArray();
String dataAsString = new String(data, "UTF-8"); // or whatever encoding you are using
You may use the following strategy as well:
class CompositeOutputStream implements OutputStream {
private OutputStream first,second;
public CompositeOutputStream(OutputStream first, OutputStream second) {
this.first = first;
this.second=second;
}
public void write(int b) throws IOException {
first.write(b);
second.write(b);
}
// etc.
}
Use with:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream os = new CompositeOutputStream(new DataOutputStream(...), baos);
os.write(...);
byte[] data = baos.toByteArray();
String dataAsString = new String(data, "UTF-8"); // or whatever encoding you are using
// etc.
The "baos" is only a "mirror" of what's got written to your original DataOutputStream
You still need to handle exceptions correctly, and be carefull about the amount of data written (holding everything in memory may lead to out of memory), etc.
Can someone explain how I can get a file object if I have only a ByteArrayOutputStream. How to create a file from a ByteArrayOutputStream?
You can do it with using a FileOutputStream and the writeTo method.
ByteArrayOutputStream byteArrayOutputStream = getByteStreamMethod();
try(OutputStream outputStream = new FileOutputStream("thefilename")) {
byteArrayOutputStream.writeTo(outputStream);
}
Source: "Creating a file from ByteArrayOutputStream in Java." on Code Inventions
You can use a FileOutputStream for this.
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File("myFile"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Put data in your baos
baos.writeTo(fos);
} catch(IOException ioe) {
// Handle exception here
ioe.printStackTrace();
} finally {
fos.close();
}