【问题标题】:How to write data to two java.io.OutputStream objects at once?如何一次将数据写入两个 java.io.OutputStream 对象?
【发布时间】:2011-12-20 16:55:22
【问题描述】:

我正在寻找可以让我执行以下操作的神奇 Java 类:

ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
FileOutputStream fileStream = new FileOutputStream(new File("/tmp/somefile"));

MultiOutputStream outStream = new MultiOutputStream(byteStream, fileStream);

outStream.write("Hello world".getBytes());

基本上,我想要tee 用于Java 中的OutputStreams。有什么想法吗?

谢谢!

【问题讨论】:

    标签: java io outputstream


    【解决方案1】:

    【讨论】:

      【解决方案2】:

      自己动手吧。根本没有任何魔法。使用Apache's TeeOutputStream,您基本上会使用下面的代码。当然,使用 Apache Commons I/O 库,您可以利用其他类,但有时实际上为自己编写一些东西会很好。 :)

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

      使用上面的类进行测试

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

      将打印Hello World!Hello World!

      (注意:被覆盖的 close() 可能需要一些小心 :)

      【讨论】:

      • 写入应该是同步的。
      • 你可以简化它。让它扩展FilterOutputStream;用super(out) 构造它;摆脱out 成员;并将所有out. 引用更改为super. 引用。
      • @Dave 取决于用例。 EJP 我更喜欢这种方式,但也可以。
      • @DaveNewton 请注意解释您关于“写入应该同步”的评论,这是强制性的吗?常规 java io 流是否使用同步关键字?
      • @Whome 不,他们没有。这里的问题(正如我在五年前看到的那样)是,由于有多次写入,您可能希望它们作为一个单元执行,以避免可能出现奇怪的输出结果排序。不过可能是错的。
      【解决方案3】:

      刚找到这个帖子,因为我不得不面对同样的问题。 如果有人想看我的解决方案(java7 代码):

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

      到目前为止工作正常,只是测试了一些基本操作,例如从 System.out 流和 2 个 PrintStream 设置一个 MultiOutputStream,每个都写入一个单独的日志。 我用过

      System.setOut(multiOutputStream);
      

      写入我的终端屏幕和两个没有任何问题的日志。

      【讨论】:

      • 我尝试使用您的代码,但是它给了我一个编译错误 - System 类型中的方法 setOut(PrintStream) 不适用于参数 (MultiOutputStream)
      • @Raj 因为OutputStream 不是PrintStream,而是相反。
      【解决方案4】:

      自己动手,这基本上是微不足道的。使用ArrayList&lt;OutputStream&gt; 或现在流行的任何东西来存储您想要的所有流,并编写write 方法来遍历所有流,写入每个流。

      【讨论】:

      • I/O 中没有什么是微不足道的。即使一开始看起来是这样。
      • 这并不能真正回答如何同时写入所有这些的问题。
      • @Kevin 不,谢谢。 for-each 循环并不能解决如何同时编写它们的问题。 for-each 将按顺序写入流,它们不会并行(即同时)写入。
      • @ZettaSuro 所以在线程中生成它们,但如果文件在同一个物理磁盘上,这不会更快,而且可能更慢,我很确定这不是 OP 的意思。它确实在一个方法调用中编写了所有流,这是手头的问题。
      • @ZettaSuro 一个方法调用而不是每次循环。设置一次流以写入您想要的所有流,然后只需 teeos.write(stuff)
      【解决方案5】:
      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());
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-16
        • 1970-01-01
        • 2022-12-01
        • 2017-12-22
        • 1970-01-01
        相关资源
        最近更新 更多