2

Javaでファイルコンバーター用の小さなGUIをプログラミングしています。ファイル コンバーターは、現在の進行状況を stdout に書き込みます。次のようになります。

Flow_1.wav: 28% complete, ratio=0,447

これを進行状況バーで説明したかったので、プロセスの stdout を次のように読んでいます。

ProcessBuilder builder = new ProcessBuilder("...");
builder.redirectErrorStream(true);
Process proc = builder.start();
InputStream stream = proc.getInputStream();
byte[] b = new byte[32];
int length;
while (true) {
    length = stream.read(b);
    if (length < 0) break;
    // processing data
}

問題は、選択したバイト配列サイズに関係なく、ストリームが 4 KB のチャンクで読み取られることです。したがって、私のコードは実行されるまで実行されlength = stream.read(b);、その後かなりの時間ブロックされます。プロセスが 4 KB の出力データを生成すると、私のプログラムはこのチャンクを取得し、32 バイトのスライスで処理します。そして、次の 4 KB を再び待ちます。

私はJavaに次のような小さなバッファを強制的に使用させようとしました:

BufferedInputStream stream = new BufferedInputStream(proc.getInputStream(), 32);

またはこれ:

BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()), 32);

しかし、どちらも何も変わりませんでした。

次に、これを見つけました:プロセスソース(87行目あたり)

Process クラスは、プロセスの stdout をファイルにパイプするような方法で実装されているようです。つまり、proc.getInputStream();実際に行うことは、ストリームをファイルに返すことです。そして、このファイルは4KBのバッファで書かれているようです。

この状況の回避策を知っている人はいますか?プロセスの出力をすぐに取得したいだけです。

EDIT : Ian Roberts が示唆したように、コンバーターの出力を stderr ストリームにパイプしようとしました。このストリームはBufferedInputStream. それでも4kチャンク。

もう 1 つの興味深い点は、実際には正確に 4096 バイトではなく、約 5 バイト多いことです。FileInputStreamそれ自体がネイティブにバッファリングされているのではないかと心配しています。

4

1 に答える 1

2

プロセスの標準出力ストリームにリンクしたコードを見ると、BufferedInputStreamその標準エラーはバッファリングされていません。そのため、コンバーターを直接実行するのではなく、コンバーターの stdout を stderr に送信するシェル スクリプト (または Windows の場合は Windows の同等のスクリプト) を実行する可能性があります。

ProcessBuilder builder = new ProcessBuilder("/bin/sh", "-c",
  "exec /path/to/converter args 1>&2");

しない で、代わりにredirectErrorStreamから読んでください。proc.getErrorStream()proc.getInputStream()

コンバーターが進行状況レポートに既に stderr を使用している場合があります。この場合、スクリプト ビットは必要ありません。オフにするだけredirectErrorStream()です。コンバーター プログラムが stdout と stderr の両方に書き込む場合は、stdout も消費するために 2 番目のスレッドを生成する必要があります (スクリプト アプローチでは、すべてを stderr に送信することでこれを回避します)。

于 2013-02-19T17:37:32.833 に答える