How to write data to two java.io.OutputStream objects at once? - java

I'm looking for magical Java class that will allow me to do something like this:
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
FileOutputStream fileStream = new FileOutputStream(new File("/tmp/somefile"));
MultiOutputStream outStream = new MultiOutputStream(byteStream, fileStream);
outStream.write("Hello world".getBytes());
Basically, I want tee for OutputStreams in Java. Any ideas?
Thanks!

Try the Apache Commons TeeOutputStream.

Just roll your own. There isn't any magic at all. Using Apache's TeeOutputStream you would basically use the code below. Of course using the Apache Commons I/O library you can leverage other classes, but sometimes it is nice to actually write something for yourself. :)
public final class TeeOutputStream extends OutputStream {
private final OutputStream out;
private final OutputStream tee;
public TeeOutputStream(OutputStream out, OutputStream tee) {
if (out == null)
throw new NullPointerException();
else if (tee == null)
throw new NullPointerException();
this.out = out;
this.tee = tee;
}
#Override
public void write(int b) throws IOException {
out.write(b);
tee.write(b);
}
#Override
public void write(byte[] b) throws IOException {
out.write(b);
tee.write(b);
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
tee.write(b, off, len);
}
#Override
public void flush() throws IOException {
out.flush();
tee.flush();
}
#Override
public void close() throws IOException {
try {
out.close();
} finally {
tee.close();
}
}
}
Testing with the above class with the following
public static void main(String[] args) throws IOException {
TeeOutputStream out = new TeeOutputStream(System.out, System.out);
out.write("Hello world!".getBytes());
out.flush();
out.close();
}
would print Hello World!Hello World!.
(Note: the overridden close() could use some care tho' :)

Just found this thread beacause I had to face the same problem.
If someone wants to see my solution (java7 code):
package Core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class MultiOutputStream extends OutputStream {
private List<OutputStream> out;
public MultiOutputStream(List<OutputStream> outStreams) {
this.out = new LinkedList<OutputStream>();
for (Iterator<OutputStream> i = outStreams.iterator(); i.hasNext();) {
OutputStream outputStream = (OutputStream) i.next();
if(outputStream == null){
throw new NullPointerException();
}
this.out.add(outputStream);
}
}
#Override
public void write(int arg0) throws IOException {
for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
OutputStream var = (OutputStream) i.next();
var.write(arg0);
}
}
#Override
public void write(byte[] b) throws IOException{
for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
OutputStream var = (OutputStream) i.next();
var.write(b);
}
}
#Override
public void write(byte[] b, int off, int len) throws IOException{
for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
OutputStream var = (OutputStream) i.next();
var.write(b, off, len);
}
}
#Override
public void close() throws IOException{
for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
OutputStream var = (OutputStream) i.next();
var.close();
}
}
#Override
public void flush() throws IOException{
for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
OutputStream var = (OutputStream) i.next();
var.flush();
}
}
}
Works fine so far, just tested some basic operation, e.g. setting up a MultiOutputStream from the System.out Stream and 2 PrintStreams each writing into a seperate log.
I used
System.setOut(multiOutputStream);
to write to my terminal screen and two logs which worked without any problems.

final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
final FileOutputStream fileStream = new FileOutputStream(new File("/tmp/somefile"));
OutputStream outStream = new OutputStream() {
public void write(int b) throws IOException {
byteStream.write(b);
fileStream.write(b);
}
};
outStream.write("Hello world".getBytes());

Roll your own, it's basically trivial. Use an ArrayList<OutputStream> or whatever's popular nowadays to store all the streams you want and write the write method to loop over all of them, writing to each.

Related

How to write console output to file and console simultaneously [duplicate]

I'm looking for magical Java class that will allow me to do something like this:
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
FileOutputStream fileStream = new FileOutputStream(new File("/tmp/somefile"));
MultiOutputStream outStream = new MultiOutputStream(byteStream, fileStream);
outStream.write("Hello world".getBytes());
Basically, I want tee for OutputStreams in Java. Any ideas?
Thanks!
Try the Apache Commons TeeOutputStream.
Just roll your own. There isn't any magic at all. Using Apache's TeeOutputStream you would basically use the code below. Of course using the Apache Commons I/O library you can leverage other classes, but sometimes it is nice to actually write something for yourself. :)
public final class TeeOutputStream extends OutputStream {
private final OutputStream out;
private final OutputStream tee;
public TeeOutputStream(OutputStream out, OutputStream tee) {
if (out == null)
throw new NullPointerException();
else if (tee == null)
throw new NullPointerException();
this.out = out;
this.tee = tee;
}
#Override
public void write(int b) throws IOException {
out.write(b);
tee.write(b);
}
#Override
public void write(byte[] b) throws IOException {
out.write(b);
tee.write(b);
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
tee.write(b, off, len);
}
#Override
public void flush() throws IOException {
out.flush();
tee.flush();
}
#Override
public void close() throws IOException {
try {
out.close();
} finally {
tee.close();
}
}
}
Testing with the above class with the following
public static void main(String[] args) throws IOException {
TeeOutputStream out = new TeeOutputStream(System.out, System.out);
out.write("Hello world!".getBytes());
out.flush();
out.close();
}
would print Hello World!Hello World!.
(Note: the overridden close() could use some care tho' :)
Just found this thread beacause I had to face the same problem.
If someone wants to see my solution (java7 code):
package Core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class MultiOutputStream extends OutputStream {
private List<OutputStream> out;
public MultiOutputStream(List<OutputStream> outStreams) {
this.out = new LinkedList<OutputStream>();
for (Iterator<OutputStream> i = outStreams.iterator(); i.hasNext();) {
OutputStream outputStream = (OutputStream) i.next();
if(outputStream == null){
throw new NullPointerException();
}
this.out.add(outputStream);
}
}
#Override
public void write(int arg0) throws IOException {
for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
OutputStream var = (OutputStream) i.next();
var.write(arg0);
}
}
#Override
public void write(byte[] b) throws IOException{
for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
OutputStream var = (OutputStream) i.next();
var.write(b);
}
}
#Override
public void write(byte[] b, int off, int len) throws IOException{
for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
OutputStream var = (OutputStream) i.next();
var.write(b, off, len);
}
}
#Override
public void close() throws IOException{
for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
OutputStream var = (OutputStream) i.next();
var.close();
}
}
#Override
public void flush() throws IOException{
for (Iterator<OutputStream> i = out.iterator(); i.hasNext();) {
OutputStream var = (OutputStream) i.next();
var.flush();
}
}
}
Works fine so far, just tested some basic operation, e.g. setting up a MultiOutputStream from the System.out Stream and 2 PrintStreams each writing into a seperate log.
I used
System.setOut(multiOutputStream);
to write to my terminal screen and two logs which worked without any problems.
final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
final FileOutputStream fileStream = new FileOutputStream(new File("/tmp/somefile"));
OutputStream outStream = new OutputStream() {
public void write(int b) throws IOException {
byteStream.write(b);
fileStream.write(b);
}
};
outStream.write("Hello world".getBytes());
Roll your own, it's basically trivial. Use an ArrayList<OutputStream> or whatever's popular nowadays to store all the streams you want and write the write method to loop over all of them, writing to each.

Read the last console output and save it to a variable/string

I want to read the last output from the console and then save it to a variable.
Let's say I have this code and output:
System.out.println("first");
System.out.println("second");
System.out.println("third");
...
**...THE CODE HERE...**
first
second
third
Now I want it to read the last/latest output from the console and save it to a variable/string.
Any ideas?
The task is quite strange, but here's quick-and-dirty solution:
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.StringWriter;
public class FilterOutput {
static class MemorizingOutputStream extends FilterOutputStream {
StringWriter sw = new StringWriter();
String last = null;
public MemorizingOutputStream(OutputStream out) {
super(out);
}
#Override
public void write(int b) throws IOException {
write(new byte[] {(byte)b}, 0, 1);
}
#Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
String s = new String(b, off, len);
int pos = s.lastIndexOf('\n');
if(pos == -1) {
sw.append(s);
} else {
int pos2 = s.lastIndexOf('\n', pos-1);
if(pos2 == -1) {
sw.append(s.substring(0, pos));
last = sw.toString();
} else {
last = s.substring(pos2+1, pos);
}
sw = new StringWriter();
sw.append(s.substring(pos+1));
}
}
public String getLast() {
return last;
}
}
public static void main(String[] args) {
MemorizingOutputStream memOut = new MemorizingOutputStream(System.out);
System.setOut(new PrintStream(memOut));
System.out.println("first");
System.out.println("second");
System.out.println("third");
System.err.println(memOut.getLast());
}
}
First it replaces the standard output stream with special stream which memorizes the last string (assuming that strings end with '\n'). Then you can query that stream for the last string which was printed. Note that this implementation is not thread-safe.

issue while extending InputStream class

I am trying to extend InputStream class and use customized read() methods.
This is my class snapshot:
class MyClass
{
/** Input stream */
private final MyInputStream in = new MyInputStream();
/**get the InputStream
public InputStream getInputStream()
{
return in;
}
/** Inner class for MyInputStream */
class MyInputStream extends InputStream
{
//here i am keeping implementation of read methods
public synchronized int read( byte b[] ) throws IOException
{
//..................
}
}
}
Here is my client class
public class MyClient {
//InStreams
protected BufferedInputStream mBufInStream;
protected DataInputStream mInStream;
public int read(byte[] buffer)
{
MyClass obj1 = new MyClass();
mBufInStream = new BufferedInputStream(obj1.getInputStream());
mInStream = new DataInputStream(mBufInStream);
try
{
int i = mBufInStream.read(buffer);
return i;
}
catch (IOException ex)
{
return -1;
}
}
public static void main(String args[])
{
MyClient cl1 = new MyClient();
int ret = 0;
byte[] data = {};
ret = cl1.read(data);
}
}
What i wanted to do is call my read method of MyInputStream Class when cl1.read is done.
I don't know what i am missing here.
I created the DataInputStream object using MyInputStream and got it working. Here is the updated code:
public class MyClient {
//InStreams
protected DataInputStream mInStream;
public int read(byte[] buffer)
{
MyClass obj1 = new MyClass();
mInStream = new DataInputStream(obj1.getInputStream());
try
{
int i = mInStream.read(buffer);
return i;
}
catch (IOException ex)
{
return -1;
}
}
public static void main(String args[])
{
MyClient cl1 = new MyClient();
int ret = 0;
byte[] data = {};
ret = cl1.read(data);
}
}
If you are extending input stream class then you will need to give the concrete definition for the following method:
public abstract int read() throws IOException
Your class has the read method with the signature as:
public int read(byte[] b) throws IOException
So please implement read() in addition to read(byte[] b). I have made some modifications and it works now...
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
public class MyClient {
//InStreams
protected BufferedInputStream mBufInStream;
protected DataInputStream mInStream;
public int read(byte[] buffer) {
MyClass obj1 = new MyClass();
// mBufInStream = new BufferedInputStream(obj1.getInputStream());
// mInStream = new DataInputStream(mBufInStream);
try {
int i = obj1.getInputStream().read(buffer);
return i;
} catch (IOException ex) {
return -1;
}
}
public static void main(String args[]) {
MyClient cl1 = new MyClient();
int ret = 0;
byte[] data = {'a','b'};
ret = cl1.read(data);
System.out.println(ret);
}
}
import java.io.IOException;
import java.io.InputStream;
class MyClass {
/** Input stream */
private final MyInputStream in = new MyInputStream();
//get the InputStream
public InputStream getInputStream() {
return in;
}
class MyInputStream extends InputStream {
//here i am keeping implementation of read methods
public int read( byte b[] ) throws IOException {
System.out.println("Inside my read()");
return b.length;
//..................
}
#Override
public int read() throws IOException {
// TODO Auto-generated method stub
return 0;
}
}
}

How to stream JSON result with Jackson in Vert.x (java)

I'm making a REST api for my Java database-like service using Vert.x.
It's not too dificult to write the JSON result as a String to the request's stream, as shown below:
...
routeMatcher.get("/myservice/api/v1/query/:query", req -> {
// get query
String querySring = req.params().get("query");
Query query = jsonMapper.readValue(querySring, Query.class);
// my service creates a list of resulting records...
List<Record> result = myservice.query(query);
String jsonResult = jsonMapper.writeValueAsString(result);
// write entire string to response
req.response().headers().set("Content-Type", "application/json; charset=UTF-8");
req.response().end(jsonResult);
});
...
However I'd like to stream the Java List to the request object by using Jackson's method:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(Outputstream, result);
But I don't know how to connect Jackson's Outputstream argument to Vert.x's re.response(), as they have their own Buffer system that seems incompatible with Jackson's java.io.Outputstream argument.
Can't I use Jackson in combination with Vert.x? Should I write a custom serializer by hand with Vert.x's own JSON library? Other suggestions?
I assume you are generating huge JSON documents as for the small ones string output is good enough: objectMapper.writeValue(<String>, result);
There's a problem with streams. ObjectMapper doesn't know the result size and you will end up with the exception:
java.lang.IllegalStateException: You must set the Content-Length header to be the total size of the message body BEFORE sending any data if you are not using HTTP chunked encoding.
at org.vertx.java.core.http.impl.DefaultHttpServerResponse.write(DefaultHttpServerResponse.java:474)
So in your example I would use temporary files for JSON output and then flush them into response (I haven't tested the code)
File tmpFile = File.createTempFile("tmp", ".json");
mapper.writeValue(tmpFile, result);
req.response().sendFile(tmpFile.getAbsolutePath(), (result) -> tmpFile.delete());
In case you know content length initially you can use the following code to map OutputStream with WriteStream
import org.vertx.java.core.buffer.Buffer;
import org.vertx.java.core.streams.WriteStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputWriterStream extends OutputStream {
public WriteStream writeStream;
public Runnable closeHandler;
#Override
public void write(int b) throws IOException {
throw new UnsupportedOperationException();
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
if (off == 0 && len == b.length) {
writeStream.write(new Buffer(b));
return;
}
byte[] bytes = new byte[len];
System.arraycopy(b, off, bytes, 0, len);
writeStream.write(new Buffer(bytes));
}
#Override
public void write(byte[] b) throws IOException {
writeStream.write(new Buffer(b));
}
#Override
public void close() throws IOException {
closeHandler.run();
}
}
This might be a bit better (and updated for Vertx3) answer:
import io.vertx.core.file.AsyncFile;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.streams.WriteStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputWriterStream extends OutputStream {
public OutputWriterStream(final WriteStream response) {
this.response = response;
this.buffer = new byte[8192];
}
#Override
public synchronized void write(final int b) throws IOException {
buffer[counter++] = (byte) b;
if (counter >= buffer.length) {
flush();
}
}
#Override
public void flush() throws IOException {
super.flush();
if (counter > 0) {
byte[] remaining = buffer;
if (counter < buffer.length) {
remaining = new byte[counter];
System.arraycopy(buffer, 0, remaining, 0, counter);
}
response.write(Buffer.buffer(remaining));
counter = 0;
}
}
#Override
public void close() throws IOException {
flush();
super.close();
if (response instanceof HttpServerResponse) {
try {
response.end();
}
catch (final IllegalStateException ignore) {
}
}
else if (response instanceof AsyncFile) {
((AsyncFile) response).close();
}
}
private final WriteStream<Buffer> response;
private final byte[] buffer;
private int counter = 0;
}

How to remove a single objects stored on Java FileOutputStream

I have used this code to store Object to a file:
try{
FileOutputStream saveFile=new FileOutputStream("SaveObj.sav");
ObjectOutputStream save = new ObjectOutputStream(saveFile);
save.writeObject(x);
save.close();
}
catch(Exception exc){
exc.printStackTrace();
}
}
}
How remove the single Object??
How clear the file??
Well, emptying out a file is very easy -- just open it for writing, and close it again:
new FileOutputStream("SaveObj.sav").close();
That will empty it out. If you were trying to erase one object out of many, though, that's a lot more complicated. You'd either have to read in all the objects and write out only the ones you want to keep, or you'd have to keep an index of the file offsets at which each object starts (probably in a separate file.) At that point you'd want to consider using an object database instead.
Ernest is right in that a removal of a particular object from the object-stream is slightly more complicated. He is also right that when you want to empty a file, you can simply open it for writing and close it. But if you want to remove it from the file-system, it is fine to do it using the File object (do not forget to handle the exceptions and return values correctly). The following example may not be perfect, but it should give you a hint on how to achieve your goals with pure Java. Hope this helps...
package test;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) throws Exception {
String filename = "object.serialized";
{
List objects = new ArrayList();
objects.add("String1");
objects.add("String2");
objects.add("String3");
writeObjectsToFile(filename, objects);
}
{
List objects = readObjectsFromFile(filename);
objects.remove(1);
writeObjectsToFile(filename, objects);
}
{
List objects = readObjectsFromFile(filename);
for (Object object : objects) {
System.out.println(object);
}
}
emptyFile(filename);
deleteFile(filename);
}
private static void emptyFile(String filename) throws IOException {
OutputStream os = null;
try {
os = new FileOutputStream(filename);
} finally {
if (os != null) {
os.close();
}
}
}
private static void deleteFile(String filename) {
File f = new File(filename);
if (f.delete()) {
System.out.println(filename + " deleted sucessfully...");
} else {
System.out.println(filename + " deletion failed!");
}
}
private static void writeObjectsToFile(String filename, List objects) throws IOException {
OutputStream os = null;
try {
os = new FileOutputStream(filename);
ObjectOutputStream oos = new ObjectOutputStream(os);
for (Object object : objects) {
oos.writeObject(object);
}
oos.flush();
} finally {
if (os != null) {
os.close();
}
}
}
private static List readObjectsFromFile(String filename) throws IOException, ClassNotFoundException {
List objects = new ArrayList();
InputStream is = null;
try {
is = new FileInputStream(filename);
ObjectInputStream ois = new ObjectInputStream(is);
while (true) {
try {
Object object = ois.readObject();
objects.add(object);
} catch (EOFException ex) {
break;
}
}
} finally {
if (is != null) {
is.close();
}
}
return objects;
}
}
Outputs:
String1
String3
object.serialized deleted sucessfully...
I know there was a long time from this subject, but just to help future coming people, what works for me was to write the object again as a null value:
public static void writeIncidentsObjectsInCache(Object object) throws IOException {
writeObject(INCIDENTS_CACHE, object); }
public static Object readIncidentsObjectFromCache() throws IOException,
ClassNotFoundException {
return readObject(INCIDENTS_CACHE); }
public static void clearIncidents() throws IOException, ClassNotFoundException {
writeIncidentsObjectsInCache(null); }
public static void writeObject(String key, Object object) throws IOException {
FileOutputStream fos = TheAAApp.getApp().openFileOutput(key, Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object);
oos.close();
fos.close();
}
public static Object readObject(String key) throws IOException,
ClassNotFoundException {
FileInputStream fis = TheAAApp.getApp().openFileInput(key);
ObjectInputStream ois = new ObjectInputStream(fis);
Object object = ois.readObject();
return object;
}

Categories