cmd.exe使用哪种编码/代码页?

300
当我在Windows上打开cmd.exe时,它使用哪种编码?
我怎样才能检查它当前正在使用的编码? 它是否取决于我的区域设置或者有没有任何环境变量来检查?
当你用特定的编码键入文件时会发生什么? 有时我得到了乱码字符(因为编码不正确),有时它还能正常工作。 但是,只要我不知道发生了什么事情,我就不相信任何东西。 能否有人解释一下?
8个回答

441

是的,有时候type和其他程序会输出乱码,有时候不会,这让人感到沮丧。

首先,Unicode字符只有在当前控制台字体包含这些字符时才能显示。因此,使用TrueType字体(如Lucida Console)而不是默认的Raster Font。

但是,如果控制台字体不包含您要显示的字符,则会看到问号而不是乱码。当您看到乱码时,除了字体设置之外,还有更多的问题。

当程序使用标准C库I/O函数(如printf)时,程序的输出编码必须与控制台的输出编码匹配,否则会出现乱码。 chcp显示并设置当前代码页。所有使用标准C库I/O函数的输出都被视为在chcp显示的代码页中。

将程序的输出编码与控制台的输出编码匹配可以通过两种不同的方式实现:

  • 程序可以使用chcpGetConsoleOutputCP获取控制台的当前代码页,并将自身配置为以该编码输出,或者

  • 您或程序可以使用chcpSetConsoleOutputCP设置控制台的当前代码页,以匹配程序的默认输出编码。

然而,使用Win32 API的程序可以直接使用WriteConsoleW将UTF-16LE字符串写入控制台。这是在不设置代码页的情况下获得正确输出的唯一方法。即使使用该函数,如果字符串最初不是UTF-16LE编码,则Win32程序必须向MultiByteToWideChar传递正确的代码页。此外,如果程序的输出被重定向,则WriteConsoleW将无法正常工作;在这种情况下需要进行更多的操作。

type 命令有时会起作用,因为它检查每个文件的开头是否有 UTF-16LE 字节顺序标记 (BOM),即字节 0xFF 0xFE。如果发现这样的标记,则无论当前代码页如何,它都将使用 WriteConsoleW 显示文件中的 Unicode 字符。但是,当 type 任何没有 UTF-16LE BOM 的文件或使用任何不调用 WriteConsoleW 的非 ASCII 字符命令时,您需要设置控制台代码页和程序输出编码以匹配。


我该如何找到这个答案呢?

这里有一个包含Unicode字符的测试文件:

ASCII     abcde xyz
German    äöü ÄÖÜ ß
Polish    ąęźżńł
Russian   абвгдеж эюя
CJK       你好

这是一个打印测试文件在许多不同Unicode编码下的Java程序。它可以使用任何编程语言; 它只会将ASCII字符或编码字节打印到stdout
import java.io.*;

public class Foo {

    private static final String BOM = "\ufeff";
    private static final String TEST_STRING
        = "ASCII     abcde xyz\n"
        + "German    äöü ÄÖÜ ß\n"
        + "Polish    ąęźżńł\n"
        + "Russian   абвгдеж эюя\n"
        + "CJK       你好\n";

    public static void main(String[] args)
        throws Exception
    {
        String[] encodings = new String[] {
            "UTF-8", "UTF-16LE", "UTF-16BE", "UTF-32LE", "UTF-32BE" };

        for (String encoding: encodings) {
            System.out.println("== " + encoding);

            for (boolean writeBom: new Boolean[] {false, true}) {
                System.out.println(writeBom ? "= bom" : "= no bom");

                String output = (writeBom ? BOM : "") + TEST_STRING;
                byte[] bytes = output.getBytes(encoding);
                System.out.write(bytes);
                FileOutputStream out = new FileOutputStream("uc-test-"
                    + encoding + (writeBom ? "-bom.txt" : "-nobom.txt"));
                out.write(bytes);
                out.close();
            }
        }
    }
}

默认代码页的输出?完全是垃圾!
Z:\andrew\projects\sx\1259084>chcp
Active code page: 850

Z:\andrew\projects\sx\1259084>java Foo
== UTF-8
= no bom
ASCII     abcde xyz
German    ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish    ąęźżńł
Russian   ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK       õ¢áÕÑ¢
= bom
´╗┐ASCII     abcde xyz
German    ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish    ąęźżńł
Russian   ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK       õ¢áÕÑ¢
== UTF-16LE
= no bom
A S C I I           a b c d e   x y z
 G e r m a n         õ ÷ ³   ─ Í ▄   ▀
 P o l i s h         ♣☺↓☺z☺|☺D☺B☺
 R u s s i a n       0123456♦  M♦N♦O♦
 C J K               `O}Y
 = bom
 ■A S C I I           a b c d e   x y z
 G e r m a n         õ ÷ ³   ─ Í ▄   ▀
 P o l i s h         ♣☺↓☺z☺|☺D☺B☺
 R u s s i a n       0♦1♦2♦3♦4♦5♦6♦  M♦N♦O♦
 C J K               `O}Y
 == UTF-16BE
= no bom
 A S C I I           a b c d e   x y z
 G e r m a n         õ ÷ ³   ─ Í ▄   ▀
 P o l i s h        ☺♣☺↓☺z☺|☺D☺B
 R u s s i a n      ♦0123456  ♦M♦N♦O
 C J K              O`Y}
= bom
■  A S C I I           a b c d e   x y z
 G e r m a n         õ ÷ ³   ─ Í ▄   ▀
 P o l i s h        ☺♣☺↓☺z☺|☺D☺B
 R u s s i a n      ♦0♦1♦2♦3♦4♦5♦6  ♦M♦N♦O
 C J K              O`Y}
== UTF-32LE
= no bom
A   S   C   I   I                       a   b   c   d   e       x   y   z
   G   e   r   m   a   n                   õ   ÷   ³       ─   Í   ▄       ▀
   P   o   l   i   s   h                   ♣☺  ↓☺  z☺  |☺  D☺  B☺
   R   u   s   s   i   a   n               0123456♦      M♦  N
♦  O♦
   C   J   K                               `O  }Y
   = bom
 ■  A   S   C   I   I                       a   b   c   d   e       x   y   z

   G   e   r   m   a   n                   õ   ÷   ³       ─   Í   ▄       ▀
   P   o   l   i   s   h                   ♣☺  ↓☺  z☺  |☺  D☺  B☺
   R   u   s   s   i   a   n               0♦  1♦  2♦  3♦  4♦  5♦  6♦      M♦  N
♦  O♦
   C   J   K                               `O  }Y
   == UTF-32BE
= no bom
   A   S   C   I   I                       a   b   c   d   e       x   y   z
   G   e   r   m   a   n                   õ   ÷   ³       ─   Í   ▄       ▀
   P   o   l   i   s   h                  ☺♣  ☺↓  ☺z  ☺|  ☺D  ☺B
   R   u   s   s   i   a   n              ♦0123456      ♦M  ♦N
  ♦O
   C   J   K                              O`  Y}
= bom
  ■    A   S   C   I   I                       a   b   c   d   e       x   y   z

   G   e   r   m   a   n                   õ   ÷   ³       ─   Í   ▄       ▀
   P   o   l   i   s   h                  ☺♣  ☺↓  ☺z  ☺|  ☺D  ☺B
   R   u   s   s   i   a   n              ♦0  ♦1  ♦2  ♦3  ♦4  ♦5  ♦6      ♦M  ♦N
  ♦O
   C   J   K                              O`  Y}

然而,如果我们键入已保存的文件,它们包含与在控制台上打印的完全相同的字节。
Z:\andrew\projects\sx\1259084>type *.txt

uc-test-UTF-16BE-bom.txt


■  A S C I I           a b c d e   x y z
 G e r m a n         õ ÷ ³   ─ Í ▄   ▀
 P o l i s h        ☺♣☺↓☺z☺|☺D☺B
 R u s s i a n      ♦0123456  ♦M♦N♦O
 C J K              O`Y}

uc-test-UTF-16BE-nobom.txt


 A S C I I           a b c d e   x y z
 G e r m a n         õ ÷ ³   ─ Í ▄   ▀
 P o l i s h        ☺♣☺↓☺z☺|☺D☺B
 R u s s i a n      ♦0♦1♦2♦3♦4♦5♦6  ♦M♦N♦O
 C J K              O`Y}

uc-test-UTF-16LE-bom.txt


ASCII     abcde xyz
German    äöü ÄÖÜ ß
Polish    ąęźżńł
Russian   абвгдеж эюя
CJK       你好

uc-test-UTF-16LE-nobom.txt


A S C I I           a b c d e   x y z
 G e r m a n         õ ÷ ³   ─ Í ▄   ▀
 P o l i s h         ♣☺↓☺z☺|☺D☺B☺
 R u s s i a n       0123456♦  M♦N♦O♦
 C J K               `O}Y

uc-test-UTF-32BE-bom.txt


  ■    A   S   C   I   I                       a   b   c   d   e       x   y   z

   G   e   r   m   a   n                   õ   ÷   ³       ─   Í   ▄       ▀
   P   o   l   i   s   h                  ☺♣  ☺↓  ☺z  ☺|  ☺D  ☺B
   R   u   s   s   i   a   n              ♦0  ♦1  ♦2  ♦3  ♦4  ♦5  ♦6      ♦M  ♦N
  ♦O
   C   J   K                              O`  Y}

uc-test-UTF-32BE-nobom.txt


   A   S   C   I   I                       a   b   c   d   e       x   y   z
   G   e   r   m   a   n                   õ   ÷   ³       ─   Í   ▄       ▀
   P   o   l   i   s   h                  ☺♣  ☺↓  ☺z  ☺|  ☺D  ☺B
   R   u   s   s   i   a   n              ♦0123456      ♦M  ♦N
  ♦O
   C   J   K                              O`  Y}

uc-test-UTF-32LE-bom.txt


 A S C I I           a b c d e   x y z
 G e r m a n         ä ö ü   Ä Ö Ü   ß
 P o l i s h         ą ę ź ż ń ł
 R u s s i a n       а б в г д е ж   э ю я
 C J K               你 好

uc-test-UTF-32LE-nobom.txt


A   S   C   I   I                       a   b   c   d   e       x   y   z
   G   e   r   m   a   n                   õ   ÷   ³       ─   Í   ▄       ▀
   P   o   l   i   s   h                   ♣☺  ↓☺  z☺  |☺  D☺  B☺
   R   u   s   s   i   a   n               0♦  1♦  2♦  3♦  4♦  5♦  6♦      M♦  N
♦  O♦
   C   J   K                               `O  }Y

uc-test-UTF-8-bom.txt


´╗┐ASCII     abcde xyz
German    ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish    ąęźżńł
Russian   ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK       õ¢áÕÑ¢

uc-test-UTF-8-nobom.txt


ASCII     abcde xyz
German    ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish    ąęźżńł
Russian   ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK       õ¢áÕÑ¢

唯一有效的是带有BOM的UTF-16LE文件,通过type打印到控制台。

如果我们使用除type之外的任何方式来打印文件,我们会得到垃圾数据:

Z:\andrew\projects\sx\1259084>copy uc-test-UTF-16LE-bom.txt CON
 ■A S C I I           a b c d e   x y z
 G e r m a n         õ ÷ ³   ─ Í ▄   ▀
 P o l i s h         ♣☺↓☺z☺|☺D☺B☺
 R u s s i a n       0123456♦  M♦N♦O♦
 C J K               `O}Y
         1 file(s) copied.

copy CON 无法正确显示Unicode的事实中,我们可以得出结论,type 命令具有检测文件开头的UTF-16LE BOM的逻辑,并使用特殊的Windows API打印它。
type 命令输出文件时,在调试器中打开 cmd.exe,我们可以看到这一点。

enter image description here

在打开文件后,type 会检查是否存在 0xFEFF 的 BOM,也就是以小端方式表示的字节 0xFF 0xFE。如果存在这样的 BOM,则 type 设置一个内部的 fOutputUnicode 标志。稍后会检查此标志来决定是否调用 WriteConsoleW

但这是唯一使 type 输出 Unicode 的方法,而且仅适用于具有 BOM 并使用 UTF-16LE 编码的文件。对于所有其他文件以及没有特殊代码处理控制台输出的程序,您的文件将根据当前代码页进行解释,并可能显示为乱码。

您可以像下面这样在自己的程序中模拟 type 输出 Unicode 到控制台:

#include <stdio.h>
#define UNICODE
#include <windows.h>

static LPCSTR lpcsTest =
    "ASCII     abcde xyz\n"
    "German    äöü ÄÖÜ ß\n"
    "Polish    ąęźżńł\n"
    "Russian   абвгдеж эюя\n"
    "CJK       你好\n";

int main() {
    int n;
    wchar_t buf[1024];

    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    n = MultiByteToWideChar(CP_UTF8, 0,
            lpcsTest, strlen(lpcsTest),
            buf, sizeof(buf));

    WriteConsole(hConsole, buf, n, &n, NULL);

    return 0;
}

这个程序可以在Windows控制台上使用默认代码页打印Unicode。


对于示例Java程序,我们可以通过手动设置代码页来获得一些正确的输出,尽管输出以奇怪的方式被搞乱:

Z:\andrew\projects\sx\1259084>chcp 65001
Active code page: 65001

Z:\andrew\projects\sx\1259084>java Foo
== UTF-8
= no bom
ASCII     abcde xyz
German    äöü ÄÖÜ ß
Polish    ąęźżńł
Russian   абвгдеж эюя
CJK       你好
ж эюя
CJK       你好
 你好
好
�
= bom
ASCII     abcde xyz
German    äöü ÄÖÜ ß
Polish    ąęźżńł
Russian   абвгдеж эюя
CJK       你好
еж эюя
CJK       你好
  你好
好
�
== UTF-16LE
= no bom
A S C I I           a b c d e   x y z
…

然而,一个设置了Unicode UTF-8代码页的C程序:
#include <stdio.h>
#include <windows.h>

int main() {
    int c, n;
    UINT oldCodePage;
    char buf[1024];

    oldCodePage = GetConsoleOutputCP();
    if (!SetConsoleOutputCP(65001)) {
        printf("error\n");
    }

    freopen("uc-test-UTF-8-nobom.txt", "rb", stdin);
    n = fread(buf, sizeof(buf[0]), sizeof(buf), stdin);
    fwrite(buf, sizeof(buf[0]), n, stdout);

    SetConsoleOutputCP(oldCodePage);

    return 0;
}

是否有正确的输出:

Z:\andrew\projects\sx\1259084>.\test
ASCII     abcde xyz
German    äöü ÄÖÜ ß
Polish    ąęźżńł
Russian   абвгдеж эюя
CJK       你好

这则故事的寓意是什么?

  • type 命令可以打印带有 BOM 的 UTF-16LE 文件,无论当前代码页是什么。
  • Win32 程序可以通过 WriteConsoleW 输出 Unicode 到控制台。
  • 其他程序可以设置代码页并相应地调整输出编码,在控制台上打印 Unicode,无论程序启动时的代码页是什么。
  • 对于其他情况,你将不得不使用 chcp 并且可能仍然会得到奇怪的输出。

2
还有一个需要学习的是微软特定扩展_setmode(_fileno(stdout), _O_U16TEXT),该扩展在VS2008中引入。 请参见https://dev59.com/WHE95IYBdhLWcg3wCJRf#9051543,https://dev59.com/HWct5IYBdhLWcg3wjd-H#12015918和http://msdn.microsoft.com/en-us/library/tw4k6df8(v=vs.90).aspx 除了_setmode()和SetConsoleOutputCP()之间明显的可移植性差异外,这两种方法中可能还存在其他微妙的副作用和隐藏的影响,这些影响并不是一眼就能完全理解的。 如果andrewdotn能够更新他的回答,并提供关于_setmode(fd,_O_U16TEXT)的任何观察结果,那将是非常好的。 - JasDev
14
虽然这是一个很好的答案,但说控制台支持UTF-16有误导性。它只支持UCS-2,即仅支持基本多文种平面(BMP)中的字符。当Win32控制台服务器(现在是conhost.exe)约于1990年设计时,Unicode是一个16位标准,因此控制台屏幕缓冲区每个字符单元使用一个16位WCHAR。UTF-16代理对打印为两个方框字符。 - Eryk Sun
4
@user200783,不支持分解形式;通常可以转换为NFC等效形式。此外,在西方语言环境中,控制台不允许混合全角和半角字符。使用代码页65001(UTF-8)时,在Windows 8之前,WriteFile 报告写入的字符数而不是字节数,因此带缓冲的写入器会根据非ASCII字符的数量多次重试“剩余”的字节。在65001中,由于在调用WideCharToMultiByte时假定每个UTF-16代码有1个ANSI字节,因此在conhost.exe中读取非ASCII字符会失败。 - Eryk Sun
2
这个简单的演示程序假设GetStdHandle(STD_OUTPUT_HANDLE)和 C stdout是控制台句柄。在实践中,要测试是否为控制台,请检查 GetConsoleMode 是否成功。同时,不要使用 C 运行时的 _isatty 函数来检查低 I/O 文件描述符是否是控制台;那只是检查字符模式设备,其中包括了 NUL 等其他内容。相反,调用 _get_osfhandle 并直接检查句柄。 - Eryk Sun
1
我已经学习了很多测试,并且想要探索更多,谢谢!有时我也会遇到终端输入的问题,所以我会采用这种方式。 - Cerberus
显示剩余4条评论

39

类型

chcp

如Dewfy所说,要查看当前的代码页。

请使用:

nlsinfo

要查看所有已安装的代码页并了解您的代码页数字的含义。

您需要安装Windows Server 2003 Resource Kit(适用于Windows XP)才能使用nlsinfo命令。


23
有趣的是,在我的Windows 7上似乎找不到“nlsinfo”。 - Joey
2
在我的Windows XP SP3机器上也不存在nlsinfo。 - Thomas Owens
3
抱歉,我认为这个工具是随 Windows Server Resource Kit 工具包提供的。我之前在我的 Windows XP SP3 机器上使用过几次,并不知道它不是默认安装的。 - Cagdas Altinkaya
啊,这就解释了为什么它出现在我安装了这些东西的Vista机器上。 - Joey
7
在 Windows 10E 计算机上也不存在 nlsinfo。需要翻译请确认。 - Yousha Aleayoub

23

针对您的第二个问题,关于编码如何工作,Joel Spolsky 写了一篇介绍性文章。强烈推荐。


15
我已经阅读并了解了这个内容。然而,在Windows系统上,我常常感到困惑,因为操作系统和大多数应用程序似乎完全不了解编码。 - Dan Gøran Lunde

7
我长期以来一直为Windows代码页问题,以及它们导致的C程序可移植性和本地化问题而感到沮丧。之前的文章已经详细介绍了这些问题,所以我不打算在这方面做任何补充。
简而言之,最终我编写了自己的UTF-8兼容性库层,覆盖了Visual C++标准C库。基本上,该库确保标准C程序在任何代码页中都能正常工作,并在内部使用UTF-8。
这个库称为MsvcLibX,可以在GitHub上获取开源版。主要功能包括:
  • C源文件使用普通char[] C字符串并采用UTF-8编码,使用标准C库API。
  • 无论在哪种代码页中,一切均在代码内部以UTF-8处理,包括主函数main()的argv[],标准输入和输出会自动转换为正确的代码页。
  • 所有stdio.h文件函数支持超过260个字符的UTF-8路径名,实际上可达到64 KB。
  • 相同的源文件可以在Windows中使用Visual C++和MsvcLibX和Visual C++ C库,在Linux中使用gcc和Linux标准C库成功编译和链接,无需使用#ifdef ... #endif块。
  • 添加了在Visual C++中缺少的包括Linux公共头文件,例如unistd.h。
  • 添加了缺少的函数,例如目录I/O和符号链接管理等,当然都带有UTF-8支持 :-)
更多详细信息请查看GitHub上MsvcLibX README,包括如何构建库及在自己的程序中使用它的说明。 上述GitHub存储库的发布部分提供了几个使用这个MsvcLibX库的程序,可以展示它的功能。例如:使用具有非ASCII名称的目录尝试我的which.exe工具,在其中搜索具有非ASCII名称的程序并更改代码页。
另一个有用的工具是conv.exe程序。该程序可以轻松将来自任何代码页的数据流转换为任何其他代码页。默认情况下,它会将Windows代码页输入,并以当前控制台代码页输出。这允许在命令行控制台中正确查看由Windows GUI应用程序(例如Notepad)生成的数据,只需使用简单的命令:type WINFILE.txt | conv 这个MsvcLibX库并不完整,欢迎贡献以改进它!

6

命令CHCP可以显示当前的代码页。它有三个数字:8xx,与Windows 12xx不同。因此,如果输入纯英文文本,您不会看到任何区别,但是扩展的代码页(如Cyrillic)将被错误地打印出来。


7
CHCP既不仅显示三位数字,也不符合8##格式。例如,437是美国编码,在英语系统中是事实标准。65001是Unicode编码(如果我没记错的话,它是UTF-8,而65000是UTF-7),可以选择使用。此外,CMD允许切换到1250代码页,但我不知道这些代码页从何时开始可供选择(这是在Win7下)。 - Adam L. S.

3
您可以通过创建文件%HOMEPATH%\init.cmd来简单地控制代码页。
我的文件如下:
@ECHO OFF
CHCP 65001 > nul

2
在Java中,我使用编码“IBM850”来写文件。这解决了问题。

1

1. 简短回答 - 将cmd.exe默认设置为使用ANSI编码

免责声明。遵循此处的任何建议都是您自己的风险。

创建并运行一个适当命名的.reg文件: 1

Windows Registry Editor Version 5.00
;; https://dev59.com/zHM_5IYBdhLWcg3wt1k0#75788701
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor]
"Autorun"="C:\\Windows\\System32\\chcp.com 1252"

如果您稍后改变主意 - 这里有一个CMD-CodePage-1252-Restore.reg文件:

Windows Registry Editor Version 5.00
;; https://dev59.com/zHM_5IYBdhLWcg3wt1k0#75788701
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor]
"Autorun"=-

2. 长答案 - 尝试回答您的所有问题

当我在Windows上打开cmd.exe时,它使用的是什么编码?

- 默认情况下,cmd.exe使用代码页437。 在我看来,这是一个糟糕的选择。
我建议改用您所使用语言的ANSI代码页。 - 它与Microsoft自己的本地文本编辑器C:\WINDOWS\System32\notepad.exe中的ANSI编码兼容。
对于西欧语言,ANSI表示代码页1252, 或Windows-1252(CP-1252)。
对于其他语言组,我在this answer的末尾发布了一张表格。

如何检查当前正在使用哪种编码?

- 运行C:\WINDOWS\System32\chcp.com

C:\>chcp
Active code page: 1252

在我的情况下,它响应1252而不是437的原因是,我故意将cmd.exe默认设置为使用1252。如上面我的“简短”答案所述。

这是否取决于我的区域设置或是否有任何环境变量需要检查?

- 都不是。在这种情况下相关的是语言。 我尝试了以下操作:
WinKey + i > 时间和语言 > 语言 > 首选语言 > 添加语言。 我添加了瑞典语(瑞典),然后确保在 Windows显示语言下选择了瑞典语
最后,我重新启动了计算机,打开了cmd.exe,输入了chcp 并按下Enter。 响应是活动代码页:437。 因此,尽管Windows显示语言更改了Windows的语言,但似乎不影响cmd.exe使用的代码页。 2

当您使用特定编码键入文件时会发生什么?

有时我会得到乱码字符(因为编码不正确),有时它似乎可以正常工作。

- 是的。这正是您应该期望的。 例如,我有一个名为Some-ANSI-chars.txt的文件,其中包含用代码页1252编码的瑞典字母åä,采用ANSI编码。
当我在cmd.exetype文件时,瑞典字母将被正确打印:

C:\stackexchange\stackoverflow\Char-encoding>type Some-ANSI-chars.txt
Sakta men säkert vinner basinkomst mark,
 och det viktigaste just nu är att hålla ihop.

但是当我复制文件并将其转换为UTF-8时, 对于每个(非ASCII)瑞典字母,会打印出两个乱码字符
C:\stackexchange\stackoverflow\Char-encoding>type Some-UTF-8-chars.txt
Sakta men säkert vinner basinkomst mark,
 och det viktigaste just nu är att hålla ihop.

正如您所见,两个UTF-8编码的字符åä使用两个字节
type命令将åä解码为每个字符两个无意义的单字节字符,即åä。对我而言,这不是问题,因为我几乎从不type我的文本文件内容。
唯一需要考虑的是,我的最爱文本编辑器设置为以UTF-8格式解码我的文件。 3

然而,只要我不知道发生了什么事,我就不相信任何东西。

- 这是明智的选择,它可以保护你(希望如此)免于陷入在cmd.exe中使用UTF-8编码的陷阱,罪魁祸首是代码页65001。

不使用UTF-8编码在cmd.exe中的原因

考虑使用MSYS2作为替代命令行工具

如果你迫切需要一个能够正确输出UTF-8编码文件文本的命令行工具,我建议你下载并安装Linux风格的MSYS2,它默认假定你的文本文件是UTF-8编码。

请注意,虽然你的UTF-8字符都被正确呈现:

$ cat Some-UTF-8-chars.txt
Sakta men säkert vinner basinkomst mark,
 och det viktigaste just nu är att hålla ihop.

非 ASCII 的 ANSI 字符将被输出为问号:

$ cat Some-ANSI-chars.txt
Sakta men s�kert vinner basinkomst mark,
 och det viktigaste just nu �r att h�lla ihop.

总之,cmd.exe 正确输出 ANSI 编码的文件, 4
而 MSYS2 终端正确输出 UTF-8 编码的文件。

参考资料


1 这个.reg文件的灵感来自于this answer。 我相信你知道如何在注册表中手动实现相同的事情。
最好先检查一下注册表,看看是否已经有一个名为Autorun的REG_SZ值。
这个注册表修改不会影响PowerShell。- 打开PowerShell并运行chcp。期望看到Active code page: 437
当然,我在我的.bat文件中也使用代码页1252。 大约99%的文件都是纯ASCII文件。

2 在进行这个实验时,我确保在注册表中的HKLM\SOFTWARE\Microsoft\Command Processor下没有Autorun值。

3 准确地说,我至少有三个“喜爱”的文本编辑器, Notepad2, Notepad++, 和Visual Studio Code
这三个编辑器中,Visual Studio Code设置为通过UTF-8编码所有文件,而Notepad2和Notepad++
自动检测编辑器认为正确的编码。

4 只要你采用了我“简短答案”中的注册表修改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接