這得從我在羣裏時不時冒泡提及。java
此刻樓上大佬裝成萌新,因此我就來了。bash
也就是看了羣裏一位老哥寫的 Flutter 組件,能夠查看當前打印的日誌,仍是挺厲害,可是打印的時候就只能調用他給定的方法來 print ,在寫安卓原生的時候有過這一需求,就是須要在 app 內部拿到 System.out.print 方法打印的字符。app
java 中則是開放了這一方法。函數
System.setErr(new PrintStream(***));
System.setOut(new PrintStream(***));
複製代碼
這樣全部的標準輸出與標準錯誤輸出都定向到了本身設置的流中,這個流能夠指向文件、管道、或是文件描述符。測試
大體相關的一些需求:ui
由於在平時的開發中,常常有被調試的手機運行着其餘的 Flutter 程序,本身的電腦終端就能拿到它的輸出。spa
在 dart 的 stdio.dart 文件中有如下幾個變量。3d
int _stdinFD = 0;
int _stdoutFD = 1;
int _stderrFD = 2;
複製代碼
還有一個重定向輸出的方法。調試
void _setStdioFDs(int stdin, int stdout, int stderr) {
_stdinFD = stdin;
_stdoutFD = stdout;
_stderrFD = stderr;
}
複製代碼
幾乎這個文件全部的東西都加上了 _ ,而咱們能拿到的只有 stdin/stdout/stderr,而且可以操做的方法也比較少。日誌
一個進程至少有 0,1,2 三個文件描述符,它們分別對應 stdin/stdout/stderr。
咱們在 c 語言用調用如下代碼:
printf('hi');
複製代碼
它其實等價於:
char tmp = "hi";
write(1, tmp, strlen(tmp));
複製代碼
因此我考慮拷貝這三個文件描述符,讓他們指向其餘的地方。
確保在父進程執行拷貝函數,fork 後的子進程的文件描述符是分開。
dup2 函數用來拷貝文件描述符。
函數原型:
int dup2 (int oldfd,int newfd)
複製代碼
若參數 newfd 已經被程序使用,則系統就會將 newfd 所指的文件關閉,若 newfd 等於 oldfd ,則返回 newfd ,而不關閉 newfd 所指的文件。dup2 所複製的文件描述符與原來的文件描述符共享各類文件狀態。共享全部的鎖定,讀寫位置和各項權限或 flags 等。
咱們調用
int filefd = open("./tmp.txt", O_RDWR);
dup2(filefd,0);
複製代碼
O_RDWR 表示可讀,可寫。
此時咱們再次調用:
printf('hi');
複製代碼
屏幕上不會再出現任何字符,輸出就直接寫入到了文件 tmp.txt 中。
因此它其實等價於:
char tmp = "hi";
write(filefd, tmp, strlen(tmp));
複製代碼
這也是僞終端實現的主要原理之一。
咱們使用 dart:ffi 來完成這個操做。
ffi 相關本文不作具體解釋。
流程就是 dart -> dart:ffi -> c -> dup2
因此咱們只須要簡單的幾行代碼。
int filefd = open("./tmp.txt", O_RDWR);
dup2(filefd, 1);
dup2(filefd, 2);
複製代碼
如此一來,開發者調用 print 函數,亦或者 dart 內部的一些打印,都等價於:
write(filefd, '***', strlen("***"));
複製代碼
全部的內容都會被定向到咱們指定的文件中
測試截圖:
在我反覆測試 Linux 桌面版與 Android 平臺的時候,發如今 Linux 的 Flutter 桌面 app 上,dart 的 print 其實就是寫入字符到文件描述符 1,2,但在 Android 設備上,print 寫入到的文件描述符是 3 ,
也就是
dup2(filefd, 3);
複製代碼
over。有問題留言。有錯誤指出。
最後歡迎各位加入Flutter Candies,一塊兒製造可愛好用的🍬 。 (QQ羣:181398081)