你如何在 Java 中合并两个输入流?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/760228/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:09:09  来源:igfitidea点击:

How do you merge two input streams in Java?

javaioinputstream

提问by pupeno

Having two InputStreams in Java, is there a way to merge them so you end with one InputStream that gives you the output of both streams? How?

在 Java 中有两个 InputStreams,有没有办法合并它们,这样你就以一个 InputStream 结束,它为你提供了两个流的输出?如何?

采纳答案by Tom Hawtin - tackline

As commented, it's not clear what you mean by merge.

正如评论的那样,目前尚不清楚您所说的合并是什么意思。

Taking available input "randomly" from either is complicated by InputStream.availablenot necessarily giving you a useful answer and blocking behaviour of streams. You would need two threads to be reading from the streams and then passing back data through, say, java.io.Piped(In|Out)putStream(although those classes have issues). Alternatively for some types of stream it may be possible to use a different interface, for instance java.nionon-blocking channels.

从任何一个“随机”获取可用输入都很复杂,InputStream.available因为不一定会给您一个有用的答案和阻塞流的行为。例如,您需要两个线程从流中读取数据,然后通过回传数据java.io.Piped(In|Out)putStream(尽管这些类有问题)。或者,对于某些类型的流,可以使用不同的接口,例如java.nio非阻塞通道。

If you want the full contents of the first input stream followed by the second: new java.io.SequenceInputStream(s1, s2).

如果您想要第一个输入流的完整内容,然后是第二个:new java.io.SequenceInputStream(s1, s2).

回答by willcodejavaforfood

Not that I can think of. You would probably have to read the contents of the two stream into a byte[] and then create a ByteArrayInputStream from that.

不是我能想到的。您可能必须将两个流的内容读入 byte[],然后从中创建一个 ByteArrayInputStream。

回答by Chris Jester-Young

You can write a custom InputStreamimplementation that does this. Example:

您可以编写一个自定义InputStream实现来执行此操作。例子:

import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Deque;
import java.util.LinkedList;

public class CatInputStream extends InputStream {
    private final Deque<InputStream> streams;

    public CatInputStream(InputStream... streams) {
        this.streams = new LinkedList<InputStream>();
        Collections.addAll(this.streams, streams);
    }

    private void nextStream() throws IOException {
        streams.removeFirst().close();
    }

    @Override
    public int read() throws IOException {
        int result = -1;
        while (!streams.isEmpty()
                && (result = streams.getFirst().read()) == -1) {
            nextStream();
        }
        return result;
    }

    @Override
    public int read(byte b[], int off, int len) throws IOException {
        int result = -1;
        while (!streams.isEmpty()
                && (result = streams.getFirst().read(b, off, len)) == -1) {
            nextStream();
        }
        return result;
    }

    @Override
    public long skip(long n) throws IOException {
        long skipped = 0L;
        while (skipped < n && !streams.isEmpty()) {
            int thisSkip = streams.getFirst().skip(n - skipped);
            if (thisSkip > 0)
                skipped += thisSkip;
            else
                nextStream();
        }
        return skipped;
    }

    @Override
    public int available() throws IOException {
        return streams.isEmpty() ? 0 : streams.getFirst().available();
    }

    @Override
    public void close() throws IOException {
        while (!streams.isEmpty())
            nextStream();
    }
}

This code isn't tested, so your mileage may vary.

此代码未经测试,因此您的里程可能会有所不同。

回答by Tom Hawtin - tackline

java.io.SequenceInputStreammight be what you need. It accepts an enumeration of streams, and will output the contents of the first stream, then the second, and so on until all streams are empty.

java.io.SequenceInputStream可能是你需要的。它接受流的枚举,并将输出第一个流的内容,然后是第二个,依此类推,直到所有流都为空。

回答by ScootyPuff

Here is an MVar implementation specific to byte arrays (make sure to add your own package definition). From here, it is trivial to write an input stream on merged streams. I can post that too if requested.

这是一个特定于字节数组的 MVar 实现(确保添加您自己的包定义)。从这里开始,在合并的流上编写输入流是微不足道的。如果需要,我也可以发布。

import java.nio.ByteBuffer;

public final class MVar {

  private static enum State {
    EMPTY, ONE, MANY
  }

  private final Object lock;

  private State state;

  private byte b;

  private ByteBuffer bytes;
  private int length;

  public MVar() {
    lock = new Object();
    state = State.EMPTY;
  }

  public final void put(byte b) {
    synchronized (lock) {
      while (state != State.EMPTY) {
        try {
          lock.wait();
        } catch (InterruptedException e) {}
      }
      this.b = b;
      state = State.ONE;
      lock.notifyAll();
    }
  }

  public final void put(byte[] bytes, int offset, int length) {
    if (length == 0) {
      return;
    }
    synchronized (lock) {
      while (state != State.EMPTY) {
        try {
          lock.wait();
        } catch (InterruptedException e) {}
      }
      this.bytes = ByteBuffer.allocateDirect(length);
      this.bytes.put(bytes, offset, length);
      this.bytes.position(0);
      this.length = length;
      state = State.MANY;
      lock.notifyAll();
    }
  }

  public final byte take() {
    synchronized (lock) {
      while (state == State.EMPTY) {
        try {
          lock.wait();
        } catch (InterruptedException e) {}
      }
      switch (state) {
      case ONE: {
        state = State.EMPTY;
        byte b = this.b;
        lock.notifyAll();
        return b;
      }
      case MANY: {
        byte b = bytes.get();
        state = --length <= 0 ? State.EMPTY : State.MANY;
        lock.notifyAll();
        return b;
      }
      default:
        throw new AssertionError();
      }
    }
  }

  public final int take(byte[] bytes, int offset, int length) {
    if (length == 0) {
      return 0;
    }
    synchronized (lock) {
      while (state == State.EMPTY) {
        try {
          lock.wait();
        } catch (InterruptedException e) {}
      }
      switch (state) {
      case ONE:
        bytes[offset] = b;
        state = State.EMPTY;
        lock.notifyAll();
        return 1;
      case MANY:
        if (this.length > length) {
          this.bytes.get(bytes, offset, length);
          this.length = this.length - length;
          synchronized (lock) {
            lock.notifyAll();
          }
          return length;
        }
        this.bytes.get(bytes, offset, this.length);
        this.bytes = null;
        state = State.EMPTY;
        length = this.length;
        lock.notifyAll();
        return length;
      default:
        throw new AssertionError();
      }
    }
  }
}