龙空技术网

混合编程—JNA 实现输出重定向

木木的代码世界 505

前言:

当前兄弟们对“javajna”都比较注重,兄弟们都想要剖析一些“javajna”的相关知识。那么小编也在网上收集了一些关于“javajna””的相关知识,希望我们能喜欢,看官们一起来学习一下吧!

有一个需求,在不影响现有 Jvm 标准输出和标准错误输出的情况下,将标准输出和标准错误输出保存下来。考虑到项目包含了 Java 和 Scala 代码,所以采用 pipe2 和 dup2 系统调用的方式来实现重定向,流程如下:

复制标准输出和标准错误输出建立非阻塞读写管道复制标准输出和标准错误输出到写管道启动另外一个线程从读管道读取内容并保存到文件,同时将内容输出到之前复制的标准输出;如果结束标志为 1,且读取多次后都失败,结束读取

样例代码如下:

/*for linux only */import com.sun.jna.*;import com.sun.jna.Memory;/** * @author mumu */public class StdCollector {  private final static int STDOUT = 1;  private final static int STDERR = 2;  private final static int O_CREAT = 64;  private final static int O_WRONLY = 1;  private final static int O_NONBLOCK = 2048;  private final static int P600 = 384;  private static int READ_BATCH = 1024;  private static int READ_INTERVAL_MS = 500;  private static int READ_RETRY = 3;  private Thread writeThread;  private volatile int stopFlag;  public interface CLibrary extends Library {    CLibrary INSTANCE = Native.loadLibrary(null, CLibrary.class);    int pipe2(Pointer p, int flag);    int dup(int fd);    int dup2(int fd1, int fd2);    int open(String path, int flag, int permission);    int read(int fd, Pointer p, int nbyte);    int write(int fd, Pointer p, int nbyte);    int close(int fd);  }  public StdCollector() {    this.stopFlag = 0;  }  public void start(String path) {    new java.io.File(path).delete();    int stdoutCopy = CLibrary.INSTANCE.dup(STDOUT);    int stderrCopy = CLibrary.INSTANCE.dup(STDERR);    // 新建管道    Pointer pipePointer = new Memory(2 * Native.getNativeSize(Integer.TYPE));    CLibrary.INSTANCE.pipe2(pipePointer, O_NONBLOCK);    // 重定向    int readFd = pipePointer.getInt(0);    int writeFd = pipePointer.getInt(Native.getNativeSize(Integer.TYPE));    CLibrary.INSTANCE.dup2(writeFd, STDOUT);    CLibrary.INSTANCE.dup2(writeFd, STDERR);    // 启动写线程    writeThread = new Thread(() -> write(path, readFd, stdoutCopy, stderrCopy));    writeThread.start();  }  public void stop() {    stopFlag = 1;    try {      writeThread.join();    } catch (Exception e) {    }  }  private void write(String path, int readFd, int stdoutCopy, int stderrCopy) {    int fd = CLibrary.INSTANCE.open(path, O_CREAT | O_WRONLY, P600);    if (fd < 0) {      CLibrary.INSTANCE.dup2(stdoutCopy, STDOUT);      CLibrary.INSTANCE.dup2(stderrCopy, STDERR);      System.err.println("建立重定向文件失败");      return;    }    Pointer p = new Memory(READ_BATCH);    try {      int retry = READ_RETRY;      while (true) {        int readCount = CLibrary.INSTANCE.read(readFd, p, READ_BATCH);        if (readCount < 0) {          Thread.sleep(READ_INTERVAL_MS);          if (stopFlag == 1 && retry <= 0) {            break;          }          retry -= 1;          continue;        }        CLibrary.INSTANCE.write(stdoutCopy, p, readCount);        CLibrary.INSTANCE.write(fd, p, readCount);        retry = READ_RETRY;      }    } catch (Exception e) {      CLibrary.INSTANCE.dup2(stdoutCopy, STDOUT);      CLibrary.INSTANCE.dup2(stderrCopy, STDERR);      e.printStackTrace();    }    CLibrary.INSTANCE.close(stdoutCopy);    CLibrary.INSTANCE.close(fd);  }  public static void main(String[] args) {    StdCollector sc = new StdCollector();    sc.start("/tmp/1");    for (int i = 0; i < 100; i++) {      System.out.println(String.format("qqqqq: %d", i));      System.err.println(String.format("wwwww: %d", i));      try { Thread.sleep(10); } catch (Exception e) {}    }    sc.stop();  }}

标签: #javajna