78

java9 の更新: https://docs.oracle.com/javase/9 ​​/docs/api/java/io/InputStream.html#transferTo-java.io.OutputStream-

似たようなスレッドをいくつか見ましたが、必要なものではありません。

サーバーは基本的にクライアント (クライアント A) から入力を受け取り、それをバイトごとに別のクライアント (クライアント B) に転送します。

クライアント A の入力ストリームをクライアント B の出力ストリームに接続したいのですが、可能ですか? それを行う方法は何ですか?

また、これらのクライアントは相互にメッセージを送信していますが、これは時間の影響を受けやすいため、バッファリングは機能しません。たとえば 500 のバッファーは必要なく、クライアントが 499 バイトを送信すると、サーバーはバッファーを満たす最後のバイトを受信して​​いないため、500 バイトの転送を保留します。

現在、各メッセージを解析して長さを確認し、長さバイトを読み取ってから転送しています。これは非常に遅いため、バイトを読み取って何度も転送するよりも優れていると考えました (そしてテストしました)。また、前の段落で述べた理由から、バッファーやタイマーを使用したくなかったのです。バッファーがいっぱいではないという理由だけで、メッセージが通過するまで非常に長い時間待機することは望ましくありません。

これを行う良い方法は何ですか?

4

10 に答える 10

86

バッファを使用するからといって、ストリームがそのバッファを埋める必要があるわけではありません。つまり、これで問題ありません。

public static void copyStream(InputStream input, OutputStream output)
    throws IOException
{
    byte[] buffer = new byte[1024]; // Adjust if you want
    int bytesRead;
    while ((bytesRead = input.read(buffer)) != -1)
    {
        output.write(buffer, 0, bytesRead);
    }
}

これで問題なく動作するはずです。基本的に、データreadが利用可能になるまで呼び出しはブロックされますが、バッファがすべて利用可能になるまで待機しません。(可能だと思います。通常はバッファいっぱいになると思いますが、ソケットに接続されたストリームはすぐにデータを提供する可能性が高くなります。)FileInputStream

少なくともこの単純な解決策を最初に試す価値があると思います。

于 2009-10-15T20:33:14.807 に答える
78

そのまま使ってみてはどうですか

void feedInputToOutput(InputStream in, OutputStream out) {
   IOUtils.copy(in, out);
}

そしてそれで終わりですか?

すでに膨大な数のプロジェクトで使用されているジャカルタのApache Commons I / Oライブラリから、クラスパスに既にjarが存在する可能性があります。

于 2012-02-28T21:53:25.460 に答える
22

完全を期すために、グアバにはこのための便利なユーティリティもあります

ByteStreams.copy(input, output);
于 2013-09-08T06:18:40.527 に答える
11

循環バッファを使用できます:

コード

// buffer all data in a circular buffer of infinite size
CircularByteBuffer cbb = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
class1.putDataOnOutputStream(cbb.getOutputStream());
class2.processDataFromInputStream(cbb.getInputStream());


Maven の依存関係

<dependency>
    <groupId>org.ostermiller</groupId>
    <artifactId>utils</artifactId>
    <version>1.07.00</version>
</dependency>


モードの詳細

http://ostermiller.org/utils/CircularBuffer.html

于 2011-11-25T01:58:39.063 に答える
9

それを達成する非同期の方法。

void inputStreamToOutputStream(final InputStream inputStream, final OutputStream out) {
    Thread t = new Thread(new Runnable() {

        public void run() {
            try {
                int d;
                while ((d = inputStream.read()) != -1) {
                    out.write(d);
                }
            } catch (IOException ex) {
                //TODO make a callback on exception.
            }
        }
    });
    t.setDaemon(true);
    t.start();
}
于 2012-06-28T00:34:51.777 に答える
3

BUFFER_SIZE は、読み込むチャックのサイズです。1kb より大きく、10MB より小さくする必要があります。

private static final int BUFFER_SIZE = 2 * 1024 * 1024;
private void copy(InputStream input, OutputStream output) throws IOException {
    try {
        byte[] buffer = new byte[BUFFER_SIZE];
        int bytesRead = input.read(buffer);
        while (bytesRead != -1) {
            output.write(buffer, 0, bytesRead);
            bytesRead = input.read(buffer);
        }
    //If needed, close streams.
    } finally {
        input.close();
        output.close();
    }
}
于 2015-04-28T09:44:57.233 に答える
2

org.apache.commons.io.IOUtils を使用する

InputStream inStream = new ...
OutputStream outStream = new ...
IOUtils.copy(inStream, outStream);

またはサイズが 2GB を超える場合はcopyLarge

于 2017-10-20T07:01:17.583 に答える
-17

関数に興味がある場合、これは Scala で書かれた関数であり、(var ではなく) val のみを使用して入力ストリームを出力ストリームにコピーする方法を示しています。

def copyInputToOutputFunctional(inputStream: InputStream, outputStream: OutputStream,bufferSize: Int) {
  val buffer = new Array[Byte](bufferSize);
  def recurse() {
    val len = inputStream.read(buffer);
    if (len > 0) {
      outputStream.write(buffer.take(len));
      recurse();
    }
  }
  recurse();
}

再帰関数を使用すると、スタック オーバーフロー例外エラーが簡単に発生する可能性があるため、利用可能なメモリがほとんどない Java アプリケーションでこれを使用することはお勧めしません。

于 2013-03-20T12:46:38.237 に答える