Golang如何在Windows终端中覆盖任意前一行内容
Golang如何在Windows终端中覆盖任意前一行内容 大家好,我正在尝试在Windows终端中重写任何先前已打印的行。为了实现这一点,我考虑将光标移动到任何先前的行,然后在其上方重新打印。
package main
import (
"bytes"
"fmt"
"os"
"os/exec"
)
func main() {
fmt.Println("line01")
fmt.Println("line02")
fmt.Println("line03")
fmt.Println("line04")
fmt.Println("line05")
fmt.Println("line06")
fmt.Println("line07")
fmt.Println("line08")
cmd := exec.Command("tput", "-S")
cmd.Stdin = bytes.NewBufferString("clear\ncup 5 2")
cmd.Stdout = os.Stdout
cmd.Run()
fmt.Println("Hello")
}
然而,看起来这段代码没有起到任何作用。有人知道如何实现吗? 这段代码的目标是:将光标移动到第6行、第3列,并显示单词“Hello”。
更多关于Golang如何在Windows终端中覆盖任意前一行内容的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang如何在Windows终端中覆盖任意前一行内容的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Windows终端中覆盖任意前一行内容需要使用Windows控制台API或ANSI转义序列。你的代码使用了tput命令,这是Unix/Linux系统的工具,在Windows上通常不可用。
以下是两种在Windows终端中实现光标移动和内容覆盖的方法:
方法1:使用ANSI转义序列(推荐)
package main
import (
"fmt"
"os"
"syscall"
"unsafe"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetStdHandle = kernel32.NewProc("GetStdHandle")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
)
const (
STD_OUTPUT_HANDLE = uintptr(4294967285) // -11
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
)
func enableVTMode() bool {
h, _, _ := procGetStdHandle.Call(STD_OUTPUT_HANDLE)
var mode uint32
procGetConsoleMode.Call(h, uintptr(unsafe.Pointer(&mode)))
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
ret, _, _ := procSetConsoleMode.Call(h, uintptr(mode))
return ret != 0
}
func main() {
// 启用ANSI转义序列支持
if !enableVTMode() {
fmt.Println("无法启用ANSI转义序列支持")
os.Exit(1)
}
fmt.Println("line01")
fmt.Println("line02")
fmt.Println("line03")
fmt.Println("line04")
fmt.Println("line05")
fmt.Println("line06")
fmt.Println("line07")
fmt.Println("line08")
// 移动光标到第6行第3列(行和列都是从1开始计数)
// \033[6;3H 移动光标到第6行第3列
// \033[2K 清除当前行
fmt.Print("\033[6;3H\033[2KHello")
// 移动光标到最后,避免后续输出位置错乱
fmt.Print("\033[9;1H")
}
方法2:使用Windows控制台API
package main
import (
"fmt"
"syscall"
"unsafe"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetStdHandle = kernel32.NewProc("GetStdHandle")
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
)
type COORD struct {
X int16
Y int16
}
func main() {
fmt.Println("line01")
fmt.Println("line02")
fmt.Println("line03")
fmt.Println("line04")
fmt.Println("line05")
fmt.Println("line06")
fmt.Println("line07")
fmt.Println("line08")
// 获取标准输出句柄
h, _, _ := procGetStdHandle.Call(uintptr(4294967285)) // STD_OUTPUT_HANDLE
// 设置光标位置(第6行第3列,注意行和列都是从0开始)
var pos COORD
pos.X = 2 // 第3列(0-based)
pos.Y = 5 // 第6行(0-based)
procSetConsoleCursorPosition.Call(h, uintptr(*(*int32)(unsafe.Pointer(&pos))))
fmt.Print("Hello")
// 移动光标到最后一行
pos.X = 0
pos.Y = 8
procSetConsoleCursorPosition.Call(h, uintptr(*(*int32)(unsafe.Pointer(&pos))))
}
方法3:使用第三方库(简化实现)
package main
import (
"fmt"
"github.com/mattn/go-colorable"
)
func main() {
// 使用支持ANSI的writer
stdout := colorable.NewColorableStdout()
fmt.Fprintln(stdout, "line01")
fmt.Fprintln(stdout, "line02")
fmt.Fprintln(stdout, "line03")
fmt.Fprintln(stdout, "line04")
fmt.Fprintln(stdout, "line05")
fmt.Fprintln(stdout, "line06")
fmt.Fprintln(stdout, "line07")
fmt.Fprintln(stdout, "line08")
// 使用ANSI转义序列移动光标
// \033[6;3H 移动到第6行第3列
fmt.Fprint(stdout, "\033[6;3HHello")
// 移动光标到最后
fmt.Fprint(stdout, "\033[9;1H")
}
要使用第三方库,需要先安装:
go get github.com/mattn/go-colorable
简单的ANSI转义序列示例
package main
import "fmt"
func main() {
// 打印多行内容
for i := 1; i <= 10; i++ {
fmt.Printf("Line %02d: Initial content\n", i)
}
// 移动光标到第5行第10列并覆盖内容
fmt.Print("\033[5;10H") // 移动到第5行第10列
fmt.Print("Overwritten!") // 覆盖内容
// 移动光标到第8行并清除整行后写入新内容
fmt.Print("\033[8;1H") // 移动到第8行第1列
fmt.Print("\033[2K") // 清除整行
fmt.Print("Completely new line content")
// 确保光标在最后
fmt.Print("\033[11;1H")
}
ANSI转义序列说明:
\033[n;mH:移动光标到第n行第m列\033[nA:光标上移n行\033[nB:光标下移n行\033[nC:光标右移n列\033[nD:光标左移n列\033[2K:清除当前行\033[s:保存光标位置\033[u:恢复光标位置
推荐使用方法1或方法3,它们使用ANSI转义序列,代码更简洁且跨平台兼容性更好(在支持ANSI的终端中都能工作)。

