我可以用Java找到控制台宽度吗?

mas*_*her 35 java console

有没有办法找到运行我的Java程序的控制台的宽度?

如果可能的话,我希望这是跨平台的......

我不想改变缓冲区或窗口的宽度,我只是想知道它的宽度,所以我可以正确地格式化正在打印到屏幕的文本.

Ste*_*n C 24

没有可靠的跨平台解决方案来解决这个问题.实际上,有些情况下无法知道真正的控制台宽度是多少.

例如,在Linux系统上,您通常可以从LINES和COLUMNS环境变量中找出名义终端维度.当您调整某些"终端仿真器"窗口的大小时,这些变量会自动更新,但情况并非总是如此.实际上,在通过telnet协议连接的远程控制台的情况下,无法将实际的终端尺寸提供给用户的shell.

编辑:只是补充一点,如果用户在启动Java应用程序后在Linux上更改了他/她的xterm的维度,则不会通知Java应用程序,并且它不会在其LINES副本中看到新维度和COLUMNS环境变量!

编辑2:我的错误,它们是bashshell变量,但默认情况下不会导出到环境中.您可以export COLUMNS LINES在运行Java应用程序之前通过运行来"修复"此问题.

  • 我使用脚本调用我的Java应用程序,脚本执行`eval \`resize \`; 在Linux下调用Java之前导出COLUMNS`. (3认同)

Mic*_*per 18

实际上,在Java中已经存在Java库:JLine 2.(在SourceForce上有一个旧版本,但是到GitHub的链接似乎是最新版本.)

在Linux(Mint 14)和Windows(我不知道是什么版本)下,这对我有用,使用JLine 2.11:

terminalWidth = jline.TerminalFactory.get().getWidth();
Run Code Online (Sandbox Code Playgroud)

JLine也承诺在Mac上工作.

我发现它1在Eclipse控制台下返回了不好的宽度(比如!)(但即使是Java的本机控制台也不能在Eclipse下工作!),不幸的是,在Cygwin下.但是我已经使用代码检查了不合理的值(< 10)并在这些情况下只使用了80.

JLine 3的更新(按Mark -thanks,mate!):

terminalWidth = org.jline.terminal.TerminalBuilder.terminal().getWidth()
Run Code Online (Sandbox Code Playgroud)

  • 在Unix上,JLine只在[`TerminalLineSetting`](https://github.com/jline/jline2/blob/master/src/main/java/jline/internal/TerminalLineSettings.java)中调用`stty -a`, Windows它通过`org.fusesource.jansi.internal.WindowsSupport`挂钩到JAnsi库的闭源部分. (6认同)

Arn*_*eur 12

您可以根据ANSI Escape Codes使用一个技巧。它们不提供查询控制台大小的直接方法,但它们确实提供了用于请求当前光标位置的命令。通过将光标移动到非常高的行和列,然后请求光标位置,您可以获得准确的测量结果。

将此与命令结合以存储/恢复光标位置,如下例所示:

将以下序列发送到终端 (stdout)

"\u001b[s"             // save cursor position
"\u001b[5000;5000H"    // move to col 5000 row 5000
"\u001b[6n"            // request cursor position
"\u001b[u"             // restore cursor position
Run Code Online (Sandbox Code Playgroud)

现在观察标准输入,您应该会收到一个类似 的序列\u001b[25;80R",其中 25 是行数,80 是列数。

我第一次看到这个是在Lanterna库中使用的。

更新:

我知道有四种不同的方法可以实现这一点,但它们都对程序运行的环境或与之通信的终端设备/模拟器做出了某些假设。

  • 使用 VT100 协议。这就是该解决方案的作用,它假设您正在通过 stdin/stdout 与支持这些转义码的终端仿真器进行对话。对于 CLI 程序来说,这似乎是一个相对安全的假设,但例如,如果有人正在使用它,cmd.exe这可能不起作用。
  • 期限信息/期限上限。这些是包含终端信息的数据库,例如您可以使用tput. 取决于操作系统,并假设您已连接到 TTY 设备。例如,不能通过 ssh 工作。
  • 使用telnet协议。Telnet 有自己的查询屏幕大小的功能,但当然这只有在人们通过 telnet 客户端连接到您的应用程序时才有效,在大多数情况下并不是真正的选项。
  • 依靠shell(例如bash),这就是使用COLUMNS/ROWS变量的解决方案所做的。远非通用,但如果您为应用程序提供一个包装脚本以确保导出必要的环境变量,则可以很好地工作。


Jac*_*nor 10

编辑:请参阅@ dave_thompson_085的评论ProcessBuilder,因为这几乎肯定是一种更好的方法.

另一个答案提到tput cols在开始命令之前在脚本中运行.但是如果你想在Java启动之后运行它Runtime.getRuntime().exec(),你会发现tput无法与你的终端通信,因为Java已经重定向了stdout和stderr.作为一种不那么便携的解决方法,您可以使用神奇的/dev/tty设备,它指的是当前进程的终端.这可以让你运行这样的东西:

Process p = Runtime.getRuntime().exec(new String[] {
    "bash", "-c", "tput cols 2> /dev/tty" });
// Read the output of this process to get your terminal width
Run Code Online (Sandbox Code Playgroud)

这在Linux上适用于我,但我不希望它在任何地方都可以工作.它有望在Mac上运行.它肯定不适用于Windows,尽管它可能与Cygwin一起使用.

  • 适用于Mac (2认同)
  • 自 Java7 (2011) 起,ProcessBuilder 可以将 Java 自己的 stdin/out/err 传递给子进程,而不是默认的重定向管道;请参阅“inheritIO()”和“redirect*(Redirect.INHERIT)”——如果“java”本身已被用户重定向,则这没有帮助,但在这种情况下,为什么你关心 I/ 的宽度您没有使用的设备? (2认同)