这得从我在群里时不时冒泡提及。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)