简体   繁体   中英

PrintWriter to multiple files

I need to write the same text to multiple files (or streams). Sometimes I need to use Writer, sometimes a PrintWriter, sometimes a OutputStream...

One way to do this wold be to extend a PrintWriter to have an array of PrintWriters and overridde each method as follows:

class MutiplePrintWriter extends PrintWriter {
    private PrintWriter[] outs;
    public MutiplePrintWriter(PrintWriter[] outs) { this.out = out; }

    public void print(boolean b) { for (PrintWriter out : outs) print(b); }
    public void print(char c) { for (PrintWriter out : outs) print(c); }
    public void print(char[] s) { for (PrintWriter out : outs) print(s); }
    ...
}   

(and the same for Writer, OutputStream...)

Is there a better alternative? Is this already implemented in a library?

You don't need to override all methods in PrintWriter , since all printXyz methods delegate to the basic write methods of the Writer API.

Although: PrintWriter has a constructor PrintWriter(Writer out) . So you need to implement only a new Writer with _one_method likes this:

public class MultiWriter implements Writer {
    private List<Writer> delegates;

    public MultiWriter(List<Writer> delegates){
        this.delegates = delegates;
    }

    public void write(char cbuf[], int off, int len) throws IOException {
        for(Writer w: delegates){
            w.writer(cbuf, off, len);
        }
    }
}

use this like this:

PrintWriter myPrinter = new PrintWriter(new MultiWriter(listOfDelegates));
myPrintWriter.println("Hello World!");

This will take care of the Writers .

You can do the same trick using OutputStream . You can also just implement MultiOutputStream , omit MultiWriter and use a delegation chain PrintWriter->OutputStreamWriter->MultiOutputStream . This would be just one method in one class to implement and you get PrintWriter , Writer and OutputStream just for free.

There are libraries out there already for this. If you can use OSS then grab Apache Commons IO and take a look at the TeeOutputStream class. Here's some sample code illustrating its use:

public class TeeOutputStreamTest {

   @Test
   public void testPrintToMultipleStreams() throws Exception {
      final String fileName1 = "/tmp/fileOne.txt";
      final String fileName2 = "/tmp/fileTwo.txt";
      final String fileName3 = "/tmp/fileThree.txt";

      final TeeOutputStream tos = new TeeOutputStream(new FileOutputStream(
              fileName1), new TeeOutputStream(new FileOutputStream(fileName2),
              new FileOutputStream(fileName3)));
      final PrintWriter writer = new PrintWriter(tos);

      writer.println("Hello World");
      writer.close();
   }
}

You can use TeeOutputStream anywhere a regular OutputStream is accepted, or wrap it in a Writer , depending on whats needed.

If you can use a Logging Library...

Use a logging library and define multiple appenders in its configuration.

You could use Apache Log4J or LogBack to that effect (I'd recommend LogBack, but to each their own).

If you are forced to use PrintWriter...

The unfortunately your solution is the best.

There's an alternative, but it's not pretty. If you are forced to pass a PrintWriter, short of providing an extension to add to the JRE's trusted libs at load time to replace PrintWriter with a class doing in effect what you suggest, I don't think you have much choice.

Well, actually you could do this easily:

instead of overriding all methods of PrintWriter class, you could override only one method of class Writer :

public void write(char cbuf[], int off, int len);

because all other methods ( print(...) and other write(...) -s) use this one:

public void write(char cbuf[], int off, int len) {
   for (Writer out : outs) out.write(cbuf, off, len);
}

UPD: also flush() and close() methods.

For OutputStream the same situation with method public void write(int b)

I prefer composition to extension. Here is another option:

public class MultiWriter
{
    List<PrintWriter> listPrintWriter = new LinkedList<PrintWriter>;
    List<Writer> listWriter = new LinkedList<Writer>;

    public void addPrintWriter(final PrintWriter newPrintWriter)
    {
        listPrintWriter.add(newPrintWriter);
    }

    public void addWriter(final Writer newWriter)
    {
        listWriter.add(newWriter);
    }

    public void write((char cbuf[], int off, int len)
    {
        if (listPrintWriter != null)
        {
            for (PrintWriter printWriter : listPrintWriter)
            {
                printWriter.write(cbuf, off, len);
            }
        }

        if (listWriter != null)
        {
            for (Writer writer : listWriter)
            {
                writer.write(cbuf, off, len);
            }
        }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM