C で開発された大きなプログラムがあり、ほとんどの関数には複数の
fprintf(stderr, "message")
行があります。
しかし今は、これらの関数を Java プログラムで使用する必要があります。そこで、Java と C の間で通信するための JNI インターフェースを実装します。すべて問題ありません。Java と C は通信できますが、Java で C のいくつかの stderr を取得したいと考えています...どうすればそれを行うことができますか?
乾杯 ;)
C で開発された大きなプログラムがあり、ほとんどの関数には複数の
fprintf(stderr, "message")
行があります。
しかし今は、これらの関数を Java プログラムで使用する必要があります。そこで、Java と C の間で通信するための JNI インターフェースを実装します。すべて問題ありません。Java と C は通信できますが、Java で C のいくつかの stderr を取得したいと考えています...どうすればそれを行うことができますか?
乾杯 ;)
まったく同じ問題を経験した私の経験から、JNIブリッジは、標準ストリームを介してJNIから出て行くものの重要性について非常に奇妙な意見を持っていることがわかります。通常、大量のキャッシュが行われ、予測できないチャンクとタイミングでこぼれますが、フラッシュを強制する方法がわかりませんでした。
*printf()
最終的に、C 側で完全に行われた、ファイルへのロギングを使用したステートメントの大量の正規表現置換が行われました。結果として得られるログファイルを追跡することは、JVM がバッファーについて考えているときではなく、C レイヤーがそう言ったときに本当にログが必要であることを JVM に納得させるどのような試みよりもはるかに信頼性がありました。
私が思いついた解決策は、次の 2 つの方法で JNI コードを作成することでした。
- stdout をパイプにリダイレクトするもの
- そこに保存された出力を取得するもの
次に、フローは次のとおりです。
- リダイレクトする関数を呼び出す
- 他の複数の JNI 呼び出しを行う
- 出力を取得し、必要な場所に書き込みます
上記のリンクから提供される実装は次のようになります
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <jni.h>
#include "Nat1.h"
#define MAXBUF 20480
static int oldstdout;
static int pipehandles[2];
static char buf[MAXBUF];
JNIEXPORT void JNICALL Java_Nat2_init(JNIEnv *cntx, jobject me)
{
oldstdout = _dup(_fileno(stdout));
_pipe(pipehandles,MAXBUF,_O_BINARY);
_dup2(pipehandles[1],_fileno(stdout));
}
JNIEXPORT jstring JNICALL Java_Nat2_done(JNIEnv *cntx, jobject me)
{
int n;
fflush(stdout);
_dup2(oldstdout,_fileno(stdout));
n = _read(pipehandles[0],buf,sizeof(buf));
buf[n] = '\0';
return (*cntx)->NewStringUTF(cntx,buf);
}
stderr のキャプチャを開始し、後でそれを表示したいときにフェッチする必要があるため、少し面倒です。
JNI ライブラリを呼び出すと、JVM プロセスにロードされるため、ライブラリの STDOUT および STDERR は JVM STDOUT および STDERR になります。したがって、質問はOS固有であり、「プロセスはどのようにして独自のSTDOUT/STDERRを読み取ることができますか?」のようなものです。
いくつかの可能性があります内部で stdout をキャプチャ/リダイレクトしますか? 、しかし、ライブラリのSTDOUTまたはSTDERRのみを読み取るのは簡単ではないと思います(私が提供する例では、リダイレクトを実行すると、コンソールを出力に使用するために戻ることはできません(*))。
コメントしたように、答えはあなたのOSに大きく依存します。
(*) 私は間違っているかもしれません。私は C/システム プログラミングが得意ではありません。
この回答に基づいて、プロセスの stderrを再割り当てできるはずです。ブロックしないように、JNI 関数の実行中にそこから読み取る別のスレッドが必要になります。