如何检查Java程序的输入/输出流是否连接到终端?

Zil*_*ilk 39 java terminal console

我希望Java程序具有不同的默认设置(详细程度,可能是支持的彩色输出),具体取决于其用途.在C中,有一个isatty()函数,如果文件描述符连接到终端,则返回1,否则返回0.在Java中是否有相同的功能?我没有在JavaDoc中看到任何有关InputStream或PrintStream的内容.

Kri*_*hus 36

System.console()vs isatty()

正如@Bombe已经提到的,System.console()适用于检查控制台连接性的简单用例.但是,System.console()的问题在于它不允许您确定连接到控制台的是STDIN还是STDOUT(或两者都兼有).

Java的System.console()和C的isatty()之间的区别可以通过以下case-breakdown(我们将数据传入/传出假设的Foo.class)来说明:

1)STDIN和STDOUT是tty

%> java Foo
System.console() => <Console instance>
isatty(STDIN_FILENO) => 1
isatty(STDOUT_FILENO) => 1
Run Code Online (Sandbox Code Playgroud)

2)STDOUT是tty

%> echo foo | java Foo
System.console() => null
isatty(STDIN_FILENO) => 0
isatty(STDOUT_FILENO) => 1
Run Code Online (Sandbox Code Playgroud)

3)STDIN是tty

%> java Foo | cat
System.console() => null
isatty(STDIN_FILENO) => 1
isatty(STDOUT_FILENO) => 0
Run Code Online (Sandbox Code Playgroud)

4)STDIN和STDOUT都不是tty

%> echo foo | java Foo | cat
System.console() => null
isatty(STDIN_FILENO) => 0
isatty(STDOUT_FILENO) => 0
Run Code Online (Sandbox Code Playgroud)

我不能告诉你为什么Java不支持更好的tty-checking.我想知道Java的一些目标操作系统是否不支持它.

使用JNI调用isatty()

从技术上讲,可以用Java(如stephen-c @指出)和一些相当简单的JNI来实现,但它会使你的应用程序依赖于可能无法移植到其他系统的C代码.我可以理解有些人可能不想去那里.

JNI的一个简单示例(掩盖了很多细节):

Java:tty/TtyUtils.java

public class TtyUtils {
    static {
        System.loadLibrary("ttyutils");
    }
    // FileDescriptor 0 for STDIN, 1 for STDOUT
    public native static boolean isTty(int fileDescriptor);
}
Run Code Online (Sandbox Code Playgroud)

C:ttyutils.c(假设匹配ttyutils.h),编译为libttyutils.so

#include <jni.h>
#include <unistd.h>

JNIEXPORT jboolean JNICALL Java_tty_TtyUtils_isTty
          (JNIEnv *env, jclass cls, jint fileDescriptor) {
    return isatty(fileDescriptor)? JNI_TRUE: JNI_FALSE;
}
Run Code Online (Sandbox Code Playgroud)

其他语言:

如果您可以选择使用其他语言,我可以考虑支持tty-checking的大多数其他语言.但是,既然你问了这个问题,你可能已经知道了.我想到的第一个问题(除了C/C++)是Ruby,Python,GolangPerl.

  • 这是[本机代码](http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/solaris/native/java/io/Console_md.c#l36)`Console`调用判断它是否存在 - "stdin"和"stdout"都必须是TTY才能使"Console"实例可用. (3认同)

Bom*_*mbe 28

System.console()将返回应用程序连接的控制台(如果已连接),否则返回null.(请注意,它仅适用于JDK 6.)

  • 如果重定向**`stdin`或`stdout`,`System.console()`将为null,但它不会告诉你它是哪一个.这是相关的,因为有时您需要知道哪个流(如果有)连接到控制台.例如,如果将`stdout`重定向到日志文件,您可能想要删除[ANSI转义码](https://en.wikipedia.org/wiki/ANSI_escape_code),但如果`stdin`是重定向. (5认同)

Ste*_*n C 9

简短的回答是标准Java中没有"isatty"的直接等价物.还有的是一个RFE用于在Java错误数据库这样的事情,因为1997年,但它只是已经1一个可怜的票.

从理论上讲,您可以使用JNI魔法实现'isatty'.但这引入了各种潜在的问题.我甚至不打算自己这样做......


1 - 在Oracle接管Sun的时候,Java错误的修复就会消失.


Leo*_*tny 6

您可以使用jnr-posix库从Java调用本机posix方法:

import jnr.posix.POSIX;
import jnr.posix.POSIXFactory;
import java.io.FileDescriptor;

POSIX posix = POSIXFactory.getPOSIX();

posix.isatty(FileDescriptor.out);
Run Code Online (Sandbox Code Playgroud)


Nei*_*gan 6

如果你不想自己编译C源代码,你可以使用Jansi库。比jnr-posix小很多

<dependency>
  <groupId>org.fusesource.jansi</groupId>
  <artifactId>jansi</artifactId>
  <version>1.17.1</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

...

import static org.fusesource.jansi.internal.CLibrary.isatty;

...

System.out.println( isatty(STDIN_FILENO) );
Run Code Online (Sandbox Code Playgroud)