我在JNA中使用C++ .so。當我通過Netbeans運行它時,C++ cout的輸出直接打印在Netbeans控制檯中。例如,我想將這個輸出重定向到一個JFrame。正如我在網上發現的其他類似主題中所建議的,我使用freopen()將stdout重定向到文件。它工作正常,但我有這個解決方案的一個問題。只有在C++代碼執行停止後(或者至少我明白 - 也許我錯了),數據才能被讀取,然後重定向到JFrame。所以我想問問,是否真的有任何方法可以將C++重定向到某些可以從Java代碼實時訪問的地方?我的意思是在執行C++代碼期間,而不是在C++部分中的操作結束之後。謝謝。重定向共享庫輸出
重定向共享庫輸出
回答
天啊..重定向到一個管道是我能想到的最糟糕的一個想法..它寫入一個文件,然後閱讀它甚至比最糟糕..
它不適合您的「實時」或「實時」數據IMO要求..
這些選項只能在「C」不是「C++」 .. C++有做你想要什麼更好的辦法..
使用你可以做的是創建你自己的流,通過JNI調用直接寫到任何你想要的地方。首先你需要繼承std::streambuf
,然後創建一個std::ostream
m您的自定義類。
重定向std::cout
的rdbuf到您的自定義流。
這裏是我寫的:
#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);
}
}
然後在Java方面我做的事:
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++調用它,而不是找到文本區域並專門追加它。如果你這樣做,那麼它可以用於任何項目和任何組件,而不僅僅是一個textarea。
這甚至可以用於文件(std::fstream
)。
反正..結果是:..
當你把它重定向:
如果您重置:
PS ..你可以用BOOST iostreams來做到這一點..它可能更容易與提升,但meh ..我已經寫了上面,所以你不妨忘了現在提升.. – Brandon 2014-09-30 18:06:41
更新了代碼..它現在更加優化和更快比以前。重定向的流將直接寫入Java的東西。 – Brandon 2014-09-30 18:26:25
你好!真的非常感謝你的非常詳細的回答/解釋。因爲我現在正在尋找這幾天,所以我找不到這麼好的答案/解釋!我會盡力像JNA那樣做,因爲我正在與它合作,否則我會採取這一點!非常感謝! :) – SpyrosR 2014-09-30 18:46:13
- 1. 共享庫輸出到標準輸出
- 2. 重定向到Facebook共享?
- 3. gdb:如何將共享庫的日誌文件重定向到gdb輸出
- 4. 定向輸出到標準輸出和共享內存
- 5. gcov:從共享庫生成.gcda輸出?
- 6. 重定向輸出
- 7. 共享htaccess:重定向多個域根
- 8. htaccess重定向到共享SSL
- 9. Facebook共享視頻重定向
- 10. Shopify:重定向共享鏈接
- 11. WinJS共享目標重定向
- 12. Wicket:重定向到共享資源
- 13. .htaccess重定向 - 兩個共享網站
- 14. 從JNI庫重定向輸出
- 15. 共享庫重定位R_X86_64_PC32錯誤
- 16. Facebook共享對話框重定向而不是彈出?
- 17. Android.mk,輸出但不包括共享庫輸出
- 18. 重新映射共享庫
- 19. 重定向輸出不輸出任何
- 20. 重定向輸出到輸出文件
- 21. 重定向輸出蟒蛇
- 22. CreateProcess並重定向輸出
- 23. 重定向崩潰輸出
- 24. C++重定向輸出
- 25. GDB Windows輸出重定向
- 26. 如何重定向輸出?
- 27. 重定向讀取輸出
- 28. 的ProcessBuilder重定向輸出
- 29. 標準輸出重定向
- 30. 重定向bash輸出
重定向到你是從讀一管。細節將在一定程度上取決於您的平臺。 – 2014-09-30 14:09:19
您可以在寫入文件時讀取文件,但命名管道最有可能更好。 – 2014-09-30 14:11:30
感謝您的答案。我嘗試使用我在此處找到的一個示例來執行此操作(讀取寫入的文件)。它在讀取文件的Java部分中使用available()方法,並在C部分中使用sleep()來查看它是否有效。它適用於此示例,但不適用於我的共享庫。你可以提出任何建議嗎?我切換到管道解決方案?謝謝。 – SpyrosR 2014-09-30 14:15:39