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.
Related
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.
I'm not a Java expert, but I know the basics of Java and I always try to understand Java code in depth always whenever it come across.
It could be a really silly doubt but would love to make it clear understanding in my mind.
I'm posting in the Java community, because my doubt is about Java only.
Since the last couple of months I am working with hadoop and came across that hadoop uses its own types, which are wrapped around Java's primitive types in order to increase efficiency to send data across network on the basis of serialization and deserialization.
My confusion starts from here, Lets say we have some data in HDFS to be processed using following Java code running in hadoop code
org.apache.hadoop.io.IntWritable;
org.apache.hadoop.io.LongWritable;
org.apache.hadoop.io.Text;
org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
public class WordCountMapper
{
extends Mapper<LongWritable,Text,Text,IntWritable>
#Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException{
}
}
String line = value.toString();
for (String word : line.split(" ")){
if(word.length()>0){
context.write(new Text(word),new IntWritable(1));
}
In this code hadoop's types are like this LongWritable, Text, IntWritable.
Lets pick up Text type which is wrapped around String type of Java (correct me if am wrong).
My doubt here is when we are passing these parameters to our method map in the above code, how these parameters gets interact with the code which is in import package i.e org.apache.hadoop.io.Text;
Below is the Text class code
package org.apache.hadoop.io;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.MalformedInputException;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Arrays;
import org.apache.avro.reflect.Stringable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience.Public;
import org.apache.hadoop.classification.InterfaceStability.Stable;
#Stringable
#InterfaceAudience.Public
#InterfaceStability.Stable
public class Text
extends BinaryComparable
implements WritableComparable<BinaryComparable>
{
private static final Log LOG = LogFactory.getLog(Text.class);
private static ThreadLocal<CharsetEncoder> ENCODER_FACTORY = new ThreadLocal()
{
protected CharsetEncoder initialValue() {
return Charset.forName("UTF-8").newEncoder().onMalformedInput(CodingErrorAction.REPORT).onUnmappableCharacter(CodingErrorAction.REPORT);
}
};
private static ThreadLocal<CharsetDecoder> DECODER_FACTORY = new ThreadLocal()
{
protected CharsetDecoder initialValue() {
return Charset.forName("UTF-8").newDecoder().onMalformedInput(CodingErrorAction.REPORT).onUnmappableCharacter(CodingErrorAction.REPORT);
}
};
private static final byte[] EMPTY_BYTES = new byte[0];
private byte[] bytes;
private int length;
public Text()
{
bytes = EMPTY_BYTES;
}
public Text(String string)
{
set(string);
}
public Text(Text utf8)
{
set(utf8);
}
public Text(byte[] utf8)
{
set(utf8);
}
public byte[] getBytes()
{
return bytes;
}
public int getLength()
{
return length;
}
public int charAt(int position)
{
if (position > length) return -1;
if (position < 0) { return -1;
}
ByteBuffer bb = (ByteBuffer)ByteBuffer.wrap(bytes).position(position);
return bytesToCodePoint(bb.slice());
}
public int find(String what) {
return find(what, 0);
}
public int find(String what, int start)
{
try
{
ByteBuffer src = ByteBuffer.wrap(bytes, 0, length);
ByteBuffer tgt = encode(what);
byte b = tgt.get();
src.position(start);
while (src.hasRemaining()) {
if (b == src.get()) {
src.mark();
tgt.mark();
boolean found = true;
int pos = src.position() - 1;
while (tgt.hasRemaining()) {
if (!src.hasRemaining()) {
tgt.reset();
src.reset();
found = false;
}
else if (tgt.get() != src.get()) {
tgt.reset();
src.reset();
found = false;
}
}
if (found) return pos;
}
}
return -1;
}
catch (CharacterCodingException e) {
e.printStackTrace(); }
return -1;
}
public void set(String string)
{
try
{
ByteBuffer bb = encode(string, true);
bytes = bb.array();
length = bb.limit();
} catch (CharacterCodingException e) {
throw new RuntimeException("Should not have happened " + e.toString());
}
}
public void set(byte[] utf8)
{
set(utf8, 0, utf8.length);
}
public void set(Text other)
{
set(other.getBytes(), 0, other.getLength());
}
public void set(byte[] utf8, int start, int len)
{
setCapacity(len, false);
System.arraycopy(utf8, start, bytes, 0, len);
length = len;
}
public void append(byte[] utf8, int start, int len)
{
setCapacity(length + len, true);
System.arraycopy(utf8, start, bytes, length, len);
length += len;
}
public void clear()
{
length = 0;
}
private void setCapacity(int len, boolean keepData)
{
if ((bytes == null) || (bytes.length < len)) {
if ((bytes != null) && (keepData)) {
bytes = Arrays.copyOf(bytes, Math.max(len, length << 1));
} else {
bytes = new byte[len];
}
}
}
public String toString()
{
try
{
return decode(bytes, 0, length);
} catch (CharacterCodingException e) {
throw new RuntimeException("Should not have happened " + e.toString());
}
}
public void readFields(DataInput in)
throws IOException
{
int newLength = WritableUtils.readVInt(in);
setCapacity(newLength, false);
in.readFully(bytes, 0, newLength);
length = newLength;
}
public static void skip(DataInput in) throws IOException
{
int length = WritableUtils.readVInt(in);
WritableUtils.skipFully(in, length);
}
public void write(DataOutput out)
throws IOException
{
WritableUtils.writeVInt(out, length);
out.write(bytes, 0, length);
}
public boolean equals(Object o)
{
if ((o instanceof Text))
return super.equals(o);
return false;
}
May I know please when ever we run the above hadoop's code, data in HDFS flows across the parameters we have mentioned in the map method.
Once the first data set from HDFS hits the Text parameter how it flows inside the org.apache.hadoop.io.Text class?
I mean from where does it start (I'm assuming it's starting from set method in class because it has kind of same parameters as mentioned map method, am I correct?)
Where does it change from normal string type to Text type in code?
My Second doubt is: when data is stored in Text type, then who kicks it to start doing serilzation? I mean who calls this write(DataOutput out), and who calls readFields(DataInput in) once data is reached to its destination on network?
How does it work, and where do I need to look?
I hope what I am asking is clear.
Like all network or disk operations, everything is transferred as bytes. The Text class deserializes bytes to UTF-8. The Writables determine how data is represented and Comparables determine how data is ordered.
The InputFormat set in the Job determines what Writables are given to a map or reduce Task.
An InputSplit determines how to split and read a raw byte stream into the Writables
One map task is started on each InputSplit
Refer https://hadoop.apache.org/docs/stable/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html
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;
}
I'm trying to make it so my program
chooses a file
reads the code one line at a time
uses an interface to do three different things
convert to uppercase
count the number of characters
save to a file ("copy.txt")
I'm stuck with the formatting parts. For instance, I'm not sure where the println commands needs to be. Any help will definitely be appreciated. I'm a beginner and still learning basic things.
Interface for Processing Individual Strings:
public interface StringProcessor
{
void process(String s);
}
Processing Class:
import java.util.Scanner;
import java.io.FileNotFoundException;
import java.io.File;
import javax.swing.JFileChooser;
class FileProcessor
{
private Scanner infile;
public FileProcessor(File f) throws FileNotFoundException
{
Scanner infile = new Scanner(System.in);
String line = infile.nextLine();
}
public String go(StringProcessor a)
{
a.process(line);
}
}
Driver Class:
import java.util.Scanner;
import java.io.FileNotFoundException;
import java.io.File;
import javax.swing.JFileChooser;
public class Driver
{
public static void main(String[] args) throws FileNotFoundException
{
JFileChooser chooser = new JFileChooser();
File inputFile = null;
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION)
{
inputFile = chooser.getSelectedFile();
}
FileProcessor infile = new FileProcessor(inputFile);
int total=0;
}
}
This Would Make Each Line Uppercase:
public class Upper implements StringProcessor
{
public void process(String s)
{
while (infile.hasNextLine())
{
System.out.println(infile.nextLine().toUpperCase());
}
}
}
This Would Count Characters:
public class Count implements StringProcessor
{
public void process(String s)
{
while (infile.hasNextLine())
{
int charactercounter = infile.nextLine().length();
total = total+charactercounter;
}
}
}
This Would Print to a File:
import java.io.PrintWriter;
import java.io.FileNotFoundException;
public class Print implements StringProcessor
{
public void process(String s)
{
PrintWriter out = new PrintWriter("copy.txt");
while (infile.hasNextLine())
{
out.println(infile.nextLine());
}
out.close();
}
}
Java was one of the first programming languages I learned and once you get it, it's so beautiful. Here is the solution for you homework, but now you have a new homework assignment. Go and figure out what is doing what and label it with notes. So next time you have a similar problem you can go over your old codes and cherry pick what you need. We were all noobs at some point so don't take it to bad.
StringProcessor.java
public interface StringProcessor {
public String Upper(String str);
public int Count(String str);
public void Save(String str, String filename);
}
FileProcessor.java
import java.io.FileWriter;
public class FileProcessor implements StringProcessor{
public FileProcessor(){
}
// Here we get passed a string and make it UpperCase
#Override
public String Upper(String str) {
return str.toUpperCase();
}
// Here we get passed a string and return the length of it
#Override
public int Count(String str) {
return str.length();
}
// Here we get a string and a file name to save it as
#Override
public void Save(String str, String filename) {
try{
FileWriter fw = new FileWriter(filename);
fw.write(str);
fw.flush();
fw.close();
}catch (Exception e){
System.err.println("Error: "+e.getMessage());
System.err.println("Error: " +e.toString());
}finally{
System.out.println ("Output file has been created: " + filename);
}
}
}
Driver.java
import java.io.File;
import java.util.Scanner;
import javax.swing.JFileChooser;
public class Driver {
#SuppressWarnings("resource")
public static void main(String[] args){
System.out.println("Welcome to the File Processor");
Scanner scan = new Scanner(System.in);
System.out.print("\nWould you like to begin? (yes or no): ");
String startProgram = scan.next();
if(startProgram.equalsIgnoreCase("yes")){
System.out.println("\nSelect a file.\n");
JFileChooser chooser = new JFileChooser();
File inputFile = null;
if(chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION){
inputFile = new File(chooser.getSelectedFile().getAbsolutePath());
try{
Scanner file = new Scanner(inputFile);
file.useDelimiter("\n");
String data = "";
FileProcessor fp = new FileProcessor();
while (file.hasNext()){
String line = file.next();
System.out.println("Original: " +line);
System.out.println("To Upper Case: " +fp.Upper(line));
System.out.println("Count: " +fp.Count(line));
System.out.println();
data += line;
}
System.out.println("\nFile Processing complete!\n");
System.out.print("Save copy of file? (yes or no): ");
String save = scan.next();
if(save.equalsIgnoreCase("yes")){
fp.Save(data, "copy.txt");
System.out.println("\nProgram Ending... Goodbye!");
}else{
System.out.println("\nProgram Ending... Goodbye!");
}
}catch (Exception e){
e.printStackTrace();
}
}
}else{
System.out.println("\nProgram Ending... Goodbye!");
}
}
}
text.txt
some text here to test the file
and to see if it work correctly
Just a note when you save the file "copy.txt", it will show up in your project folder.
As your problem operates on streams of characters, there is already a good Java interface to implement. Actually, they are two abstract classes: FilterReader or FilterWriter — extending either one will work. Here, I've chosen to extend FilterWriter.
For example, here is an example of a Writer that keeps track of how many characters it has been asked to write:
import java.io.*;
public class CharacterCountingWriter extends FilterWriter {
private long charCount = 0;
public CharacterCountingWriter(Writer out) {
super(out);
}
public void write(int c) throws IOException {
this.charCount++;
out.write(c);
}
public void write(char[] buf, int off, int len) throws IOException {
this.charCount += len;
out.write(buf, off, len);
}
public void write(String str, int off, int len) throws IOException {
this.charCount += len;
out.write(str, off, len);
}
public void resetCharCount() {
this.charCount = 0;
}
public long getCharCount() {
return this.charCount;
}
}
Based on that model, you should be able to implement a UpperCaseFilterWriter as well.
Using those classes, here is a program that copies a file, uppercasing the text and printing the number of characters in each line as it goes.
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new FileReader(args[0]));
try (CharacterCountingWriter ccw = new CharacterCountingWriter(new FileWriter(args[1]));
UpperCaseFilterWriter ucfw = new UpperCaseFilterWriter(ccw);
Writer pipeline = ucfw) { // pipeline is just a convenient alias
String line;
while (null != (line = in.readLine())) {
// Print count of characters in each line, excluding the line
// terminator
ccw.resetCharCount();
pipeline.write(line);
System.out.println(ccw.getCharCount());
pipeline.write(System.lineSeparator());
}
pipeline.flush();
}
}
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.