我正在尝试通过Windows上的go语言重建类似tee的util。 但我发现输出的编码并不总是一样的。
为了简化问题,我编写了这个程序:
package main
import (
"fmt"
"io"
"os"
)
func main() {
count, err := io.Copy(os.Stdout, os.Stdin)
fmt.Println(count, err)
}
我把它命名为test。 在Windows命令控制台中,我得到了这些输出:
>test
中
中
5 <nil>
没有管道和重定向它工作正常。
>echo 中 | test
��
5 <nil>
如果我从管道获取stdin,则输出会崩溃。
>echo 中 | test > test.txt
>type test.txt
中
5 <nil>
当我将输出重定向到文件时,它再次起作用。
>test > test.txt
中
>type test.txt
荳ュ
5 <nil>
但是当我使用普通的stdin并重定向到文件时不起作用。
如果我在其他编辑器(如notepad ++)中打开此test.txt,我发现它以UTF-8编码,内容为中
。
如果我在Windows上使用带有UTF-8编码控制台的Cygwin,一切都很好。
从输出中,我知道程序复制的字节数是5,这意味着无论stdin是什么,它都在程序中使用UTF-8。 但是我知道windows命令行控制台基本上是使用非unicode编码,为什么它被转换成UTF-8?有没有办法让程序只是复制stdin发送的内容而不进行任何转换?
顺便说一句。如果我使用gnuWin32中的tee进行同样的测试,一切都运行良好。
>where tee
D:\Tools\gnuWin32\bin\tee.exe
>echo 中 | tee
中
>tee tee.txt
中
中
^C
>type tee.txt
中
有没有人知道这个的原因以及解决方案是什么?
答案 0 :(得分:0)
它不使用utf8,为什么写入5个字节是因为中间有一个空格(0x20)
C:\Users\jan>echo 中| go run src/main.go
00000000 d6 d0 0d 0a |....|
��
4 <nil>
所以在我的系统中,控制台不使用utf8,而是使用GBK。
该错误是因为Windows控制台无法更改屏幕上的字符,即使附加的字节使字符成为另一个字符。例如&#39; d6 d0&#39;是中,d6已在屏幕上显示为�,0a附加,不使两个字节成为一个显示字符。
进行测试,我有一个c#控制台程序
static void Main(string[] args)
{
using (Stream stdout = Console.OpenStandardOutput())
{
stdout.WriteByte((byte)'A');
stdout.WriteByte(0xd6);
stdout.WriteByte(0xd0);
}
using (Stream stdout = Console.OpenStandardOutput())
{
stdout.WriteByte((byte)'B');
stdout.WriteByte(0xd6);
}
using (Stream stdout = Console.OpenStandardOutput())
{
stdout.WriteByte(0xd0);
}
}
得到结果:
A中BPress any key to continue . . .
所以我猜windows libc在stdout之前有一个缓冲区,它组成两个字节是一个字符并打印到控制台。
我发现有趣的是,即使windows控制台在gbk页面中,go lang也可以使用utf8编码编写stdou。似乎字节写入os.Stdout
并没有直接传递给控制台。
package main
import (
"fmt"
"os"
)
func main() {
os.Stdout.Write([]byte{0xe4,0xb8,0xad})
fmt.Print("\xe4")
fmt.Print("\xb8")
fmt.Println("\xad")
}
得到:
C:\Users\jan>go run src/main.go
中中
C:\Users\jan>