JNA에서 C++ .so를 사용하고 있습니다. Netbeans를 통해 실행할 때 C++ 출력은 Netbeans 콘솔에 직접 인쇄됩니다. 이 출력을 예를 들어 JFrame으로 리디렉션하고 싶습니다. 웹에서 찾은 다른 유사한 주제에서 제안한 것처럼 freopen()을 사용하여 stdout을 파일로 리디렉션했습니다. 그것은 잘 작동하지만이 솔루션에는 한 가지 문제가 있습니다. 데이터는 C++ 코드의 실행이 중지 된 후에 만 (또는 적어도 이해할 수 있습니다 - 어쩌면 내가 틀 렸음) 원하는대로 JFrame을 읽은 다음 JFrame으로 리디렉션 할 수 있습니다. 그래서 실시간으로 내 Java 코드에서 액세스 할 수있는 C++ 출력을 리디렉션 할 수있는 방법이 있는지 묻고 싶습니다. 내 말은 C++ 코드를 실행하는 동안이 아니라 C++ 부분에서 작업이 끝난 후에가 아니라는 뜻입니다. 감사.리디렉션 공유 라이브러리 출력
답변
오 신 .. 파이프로 리디렉션하는 것은 .. 내가 생각할 수있는 최악의 아이디어 중 하나입니다보다에서도 최악의 그것을 읽고 다음 파일로 작성하고 ..
이 맞지 않는
이러한 옵션은 단지 "C"없습니다 "C++".. C++은 당신이 원하는 일을 더 나은 방법이있다 ..
에 사용되어야한다 "실시간"또는 IMO "라이브"데이터의 당신의 필요 조건 ...당신이 할 수있는 일은 JNI 호출을 통해 원하는 곳으로 직접 쓰는 스트림을 직접 생성하는 것입니다. 먼저 std::streambuf
에서 상속 받아야하며 std::ostream
사용자 지정 클래스를 만들었습니다.
std::cout
의 사용자 지정 스트림으로 리디렉션합니다. 여기
#include "jni.h"
#include <tuple>
#include <vector>
#include <iostream>
#include <cstring>
#if defined _WIN32 || defined _WIN64
#include <windows.h>
#else
#include <sys/types.h>
#endif
#if defined _WIN32 || defined _WIN64
#define JAVA_EXPORT __declspec(dllexport)
#else
#define JAVA_EXPORT
#endif
std::vector<std::tuple<std::ostream*, std::ios*, std::streambuf*>> streams;
extern "C" {
JAVA_EXPORT void Java_natives_Natives_RedirectOutput(JNIEnv* env, jclass cls, jobject component);
JAVA_EXPORT void Java_natives_Natives_ResetOutput(JNIEnv* env, jclass cls);
}
class redir : public std::streambuf
{
private:
JNIEnv* env;
jobject comp;
jmethodID mID;
int_type overflow(int_type c = traits_type::eof());
public:
redir(JNIEnv* e, jobject comp, jmethodID m) : env(env), comp(comp), mID(mID) {}
~redir() {}
redir(const redir& other) = delete;
redir& operator = (const redir& other) = delete;
};
redir::int_type redir::overflow(redir::int_type c)
{
if (c != traits_type::eof())
{
jstring str = env->NewStringUTF((char*)&c);
env->CallVoidMethod(comp, mID, str);
}
return c;
}
class rdstream : public std::ostream
{
public:
rdstream(JNIEnv* env, jobject comp, jmethodID mID) : std::ostream(0), sbuf(env, comp, mID) {init(&sbuf);}
private:
redir sbuf;
};
void Java_natives_Natives_RedirectOutput(JNIEnv* env, jclass cls, jobject component)
{
if (streams.empty())
{
jclass txtcls = env->FindClass("Ljavax/swing/JTextArea;");
if (txtcls)
{
jmethodID app = env->GetMethodID(txtcls, "append", "(Ljava/lang/String;)V");
rdstream* ctrd = new rdstream(env, component, app);
rdstream* crrd = new rdstream(env, component, app);
streams.push_back(std::make_tuple(ctrd, &std::cout, std::cout.rdbuf()));
streams.push_back(std::make_tuple(crrd, &std::cerr, std::cerr.rdbuf()));
std::cout.rdbuf(ctrd->rdbuf());
std::cerr.rdbuf(crrd->rdbuf());
std::cout<<"TESTING OUTPUT REDIRECTION\n";
}
}
}
void Java_natives_Natives_ResetOutput(JNIEnv* env, jclass cls)
{
for (std::vector<std::tuple<std::ostream*, std::ios*, std::streambuf*>>::iterator it = streams.begin(); it != streams.end(); ++it)
{
std::get<1>(*it)->rdbuf(std::get<2>(*it));
delete std::get<0>(*it);
}
streams.clear();
std::cout<<"TESTING OUTPUT RESET\n"<<std::flush;
}
void __attribute__((constructor)) load()
{
//Onload..
}
void __attribute__((destructor)) unload()
{
//OnUnload..
if (!streams.empty())
{
Java_natives_Natives_ResetOutput(NULL, NULL);
}
}
:
package natives;
import java.awt.Component;
/**
*
* @author Brandon
*/
public class Natives {
static {
System.loadLibrary("Redirector");
}
public native static void RedirectOutput(Component comp);
public native static void ResetOutput();
}
및 테스트 클래스 : 이제
package windowhandle;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JTextArea;
/**
*
* @author Brandon
*/
public class WindowHandle {
public static void main(String[] args) {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
JTextArea t = new JTextArea();
t.setPreferredSize(new Dimension(500, 100));
f.setLayout(new BorderLayout(0, 0));
f.getContentPane().add(t, BorderLayout.CENTER);
f.pack();
natives.Natives.RedirectOutput(t);
natives.Natives.ResetOutput();
}
}
는 C++ 코드가 될 수 있습니다 원하는 방식으로 사용자 정의 할 수 있습니다. Java 측에서 원하는 구성 요소를 추가 한 다음 C++에서 텍스트 영역을 찾고 구체적으로 추가하는 대신 해당 메서드를 호출 할 수있는 메서드를 만들 수 있습니다. 이렇게하면 모든 프로젝트에 사용할 수 있습니다. 텍스트 영역뿐만 아니라 모든 구성 요소에 적용됩니다.
파일 (std::fstream
)에도 사용할 수 있습니다.
어쨌든 .. 결과는 다음과 같습니다 ..
당신이 그것을 리디렉션하는 경우 :
당신이 그것을 재설정하면 :
추 ..당신은 또한 BOOST iostreams로 이것을 할 수 있습니다 .. 아마도 boost가 있지만 meh .. 아마 이미 위를 썼습니다. 그래서 지금은 boost에 대해 잊어 버릴지도 모릅니다. – Brandon
코드가 업데이트되었습니다. 이제 더 최적화되고 빨라졌습니다. 전보다. 리디렉션 된 스트림은 Java 항목에 직접 씁니다. – Brandon
안녕하세요! 매우 상세한 답변/설명에 정말 감사드립니다. 지금 이틀 동안 이것을 찾고 있기 때문에 나는 아주 좋은 대답/설명을 찾을 수 없었다! 나는 JNA와 함께 그렇게하려고 노력할 것입니다. 그렇지 않으면 JNA와 협력 할 것입니다. 다시 한번 대단히 감사합니다! :) – SpyrosR
- 1. 출력 리디렉션
- 2. 공유 라이브러리
- 3. 공유 라이브러리
- 4. 공유 라이브러리
- 5. Android : 동적 공유 라이브러리 공유
- 6. 공유 라이브러리를 서로 공유 라이브러리 공유 C++
- 7. Facebook 공유 비디오 리디렉션
- 8. WinJS 공유 대상 리디렉션
- 9. Capistrano의 출력 리디렉션
- 10. 리디렉션 명령 출력
- 11. 파이썬에서 출력 파일 리디렉션
- 12. 오디오 출력 리디렉션
- 13. 리디렉션 프로세스 출력
- 14. 출력 파일 설명자 리디렉션
- 15. 출력 리디렉션 내부/배쉬
- 16. UNIX에서 출력 리디렉션
- 17. 리디렉션 프로세스 출력 C#
- 18. Powershell : 출력 리디렉션 문제
- 19. Java에서 출력 리디렉션
- 20. BASH 평가 출력 리디렉션
- 21. C++ 리디렉션 출력
- 22. GDB Windows 출력 리디렉션
- 23. 끊임없이 출력 업데이트 리디렉션
- 24. 출력 후 PHP 리디렉션
- 25. 리디렉션 화면 출력
- 26. 시간 출력 리디렉션
- 27. bash 출력 리디렉션 prob
- 28. Linux에서 파일 출력 리디렉션
- 29. 리디렉션 콘솔 출력
- 30. 내가 사용하는 공유 라이브러리 A가 라이브러리 B를 공유 한 리눅스
당신이에서 읽고있는 파이프로 리디렉션합니다. 세부 사항은 플랫폼에 따라 어느 정도 다릅니다. –
작성된대로 파일을 읽을 수는 있지만 명명 된 파이프가 가장 적합 할 수 있습니다. –
답변 해 주셔서 감사합니다. 내가 여기에서 찾은 한 가지 예를 사용하여 당신이 언급 한 것을 시도했다. 파일을 읽는 Java 파트에서 available() 메서드를 사용하고 C 파트에서 sleep()을 사용하여 작동하는지 확인합니다. 이 예제에서는 작동하지만 공유 라이브러리에서는 작동하지 않습니다. 당신이 파이프 솔루션으로 바꾼다는 것에 대해 아무 것도 제안 할 수 있습니까? 감사. – SpyrosR