cmd.exe使用什么编码/代码页?

dan*_*und 258 windows encoding command-line

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

如何查看当前使用的编码?它取决于我的区域设置还是有任何环境变量需要检查?

键入具有特定编码的文件时会发生什么?有时我会收到乱码(使用的编码不正确),有时候它会有所作为.但是,只要我不知道发生了什么,我就不相信任何事情.谁能解释一下?

and*_*otn 376

是的,这令人沮丧 - 有时候type,其他程序打印出胡言乱语,有时他们却没有.

首先,只有当前控制台字体包含字符时才会显示Unicode 字符.因此,使用像Lucida Console这样的TrueType字体而不是默认的Raster字体.

但如果控制台字体不包含您要显示的字符,您将看到问号而不是乱码.当你得到胡言乱语时,除了字体设置之外还有更多的东西.

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

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

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

  • 您或程序可以使用chcp或 设置控制台的当前代码页SetConsoleOutputCP来匹配程序的默认输出编码.

但是,使用Win32 API的程序可以直接将UTF-16LE字符串写入控制台 WriteConsoleW.这是在不设置代码页的情况下获得正确输出的唯一方法.即使使用该函数,如果字符串不是UTF-16LE编码开头,Win32程序必须将正确的代码页传递给 MultiByteToWideChar.此外,WriteConsoleW如果重定向程序的输出,则无效; 在这种情况下需要更多的摆弄.

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


我们怎么能找到这个呢?

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

ASCII     abcde xyz
German    äöü ÄÖÜ ß
Polish    ??????
Russian   ??????? ???
CJK       ??
Run Code Online (Sandbox Code Playgroud)

这是一个Java程序,用于在一堆不同的Unicode编码中打印出测试文件.它可以是任何编程语言; 它只打印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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

默认代码页中的输出?总垃圾!

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       0?1?2?3?4?5?6?  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      ?0?1?2?3?4?5?6  ?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               0?  1?  2?  3?  4?  5?  6?      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              ?0  ?1  ?2  ?3  ?4  ?5  ?6      ?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}
Run Code Online (Sandbox Code Playgroud)

但是,如果我们type保存的文件怎么办?它们包含打印到控制台的完全相同的字节.

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      ?0?1?2?3?4?5?6  ?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       0?1?2?3?4?5?6?  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              ?0  ?1  ?2  ?3  ?4  ?5  ?6      ?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       õ¢áÕÑ¢
Run Code Online (Sandbox Code Playgroud)

唯一的作品就是UTF-16LE文件,以BOM,打印到通过控制台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       0?1?2?3?4?5?6?  M?N?O?
 C J K               `O}Y
         1 file(s) copied.
Run Code Online (Sandbox Code Playgroud)

copy CON从未正确显示Unicode 的事实来看,我们可以得出结论,该type命令具有在文件开头检测UTF-16LE BOM的逻辑,并使用特殊的Windows API来打印它.

我们可以通过cmd.exe在调试器中打开type 文件时打开它来看到:

在此输入图像描述

之后type打开一个文件,它会检查的BOM 0xFEFF-即字节 0xFF 0xFE的小端,如果有这样的BOM,type设置内部fOutputUnicode标志.稍后检查该标志以决定是否呼叫WriteConsoleW.

但这是获得typeUnicode输出的唯一方法,仅适用于具有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;
}
Run Code Online (Sandbox Code Playgroud)

此程序适用于使用默认代码页在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
…
Run Code Online (Sandbox Code Playgroud)

但是,一个设置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;
}
Run Code Online (Sandbox Code Playgroud)

确实有正确的输出:

Z:\andrew\projects\sx\1259084>.\test
ASCII     abcde xyz
German    äöü ÄÖÜ ß
Polish    ??????
Russian   ??????? ???
CJK       ??
Run Code Online (Sandbox Code Playgroud)

这个故事的主旨?

  • type 无论您当前的代码页如何,都可以使用BOM打印UTF-16LE文件
  • Win32程序可以编程为使用输出Unicode到控制台 WriteConsoleW.
  • 其他设置代码页并相应调整其输出编码的程序可以在控制台上打印Unicode,无论程序启动时代码页是什么
  • 对于其他一切你将不得不陷入困境chcp,并可能仍然会得到奇怪的输出.

  • 哇,这一定是我见过的最详细的答案.对于dissasembly打印和多语言技能的额外功劳!只是美丽,先生! (69认同)
  • 虽然这是一个很好的答案,但是说控制台支持UTF-16会产生误导.它仅限于UCS-2,即仅限于基本多语言平面(BMP)中的字符.当Win32控制台服务器(现在是conhost.exe)大约在1990年设计时,Unicode是一个16位标准,因此控制台屏幕缓冲区每个字符单元使用一个16位WCHAR.UTF-16代理对打印为两个框字符. (12认同)
  • @ user200783,不支持分解形式; 通常可以转换为NFC等效物.此外,Western语言环境中的控制台不允许混合全宽和半宽字形.此外,当使用代码页65001(UTF-8)时,在Windows 8之前``WriteFile`报告写入的字符数而不是字节数,因此缓冲的写入器按照非数字的比例重试"剩余"字节几次-ASCII字符.同样在65001中,在conhost.exe中读取非ASCII字符失败,因为它在调用"WideCharToMultiByte"时假定每个UTF-16代码有1个ANSI字节. (3认同)
  • 人们可能还想研究VS2008中引入的特定于Microsoft的扩展_setmode(_fileno(stdout),_O_U16TEXT).请参阅http://stackoverflow.com/a/9051543和http://stackoverflow.com/a/12015918,以及http://msdn.microsoft.com/en-us/library/tw4k6df8(v=vs.90 ).aspx除了_setmode()和SetConsoleOutputCP()之间明显的可移植性差异外,两种方法中还可能隐藏其他细微之处和副作用,乍看之下尚未完全理解.如果andrewdotn可以用任何关于_setmode(fd,_O_U16TEXT)的观察来更新他的答案,那就太棒了. (2认同)
  • 此答案中的简单演示程序假定`GetStdHandle(STD_OUTPUT_HANDLE)`和C`stdout`是控制台句柄。实际上,要测试控制台,请检查[`GetConsoleMode`](https://msdn.microsoft.com/zh-cn/library/ms683167)是否成功。另外,不要使用C运行时`_isatty`函数来检查低I / O文件描述符是否是控制台。仅检查字符模式设备,其中包括“ NUL”。而是调用[`_get_osfhandle`](https://msdn.microsoft.com/zh-cn/library/ks2530z6)并直接检查句柄。 (2认同)

Cag*_*aya 27

类型

chcp
Run Code Online (Sandbox Code Playgroud)

查看您当前的代码页(正如Dewfy已经说过的那样).

使用

nlsinfo
Run Code Online (Sandbox Code Playgroud)

查看所有已安装的代码页并找出代码页编号的含义.

您需要安装Windows Server 2003资源工具包(适用于Windows XP)才能使用nlsinfo.

  • 有趣的是,`nlsinfo`似乎不存在于我的Windows 7上. (17认同)
  • 我的Windows XP SP3机器上也不存在`nlsinfo`. (2认同)
  • 哦,对不起.我认为它附带Windows Server Resource Kit工具.我早些时候在我的Windows XP SP3机器上使用了它几次,并且不知道默认情况下没有安装它. (2认同)
  • Windows 10E计算机上也不存在`nlsinfo`。 (2认同)

Bri*_*new 21

要回答你的第二个问题.编码如何运作,Joel Spolsky写了一篇很棒的介绍性文章.强力推荐.

  • 我读过它而且我知道它.然而,在Windows上我总是感到迷茫,因为操作系统和大多数应用程序似乎完全不了解编码. (13认同)

Jea*_*ire 7

长期以来,我一直对 Windows 代码页问题以及它们引起的 C 程序可移植性和本地化问题感到沮丧。之前的帖子已经详细介绍了这些问题,因此我不会在这方面添加任何内容。

长话短说,最终我在 Visual C++ 标准 C 库上编写了自己的 UTF-8 兼容库层。基本上,这个库确保标准 C 程序在任何代码页中都能正常工作,内部使用 UTF-8。

该库称为 MsvcLibX,可在https://github.com/JFLarvoire/SysToolsLib上以开源方式获取。主要特点:

  • 使用普通 char[] C 字符串和标准 C 库 API 以 UTF-8 编码的 C 源代码。
  • 在任何代码页中,所有内容都在代码中以 UTF-8 形式进行内部处理,包括 main() 例程 argv[],标准输入和输出会自动转换为正确的代码页。
  • 所有 stdio.h 文件函数都支持 UTF-8 路径名 > 260 个字符,实际上最多 64 KB。
  • 相同的源可以在 Windows 中使用 Visual C++ 和 MsvcLibX 以及 Visual C++ C 库成功编译和链接,在 Linux 中使用 gcc 和 Linux 标准 C 库成功编译和链接,无需 #ifdef ... #endif 块。
  • 添加 Linux 中常见但 Visual C++ 中缺少的包含文件。例如:unistd.h
  • 添加缺少的功能,例如目录 I/O、符号链接管理等,当然所有这些都支持 UTF-8 :-)。

更多详细信息,请参阅GitHub 上的 MsvcLibX 自述文件,包括如何构建该库并在您自己的程序中使用它。

上述 GitHub 存储库中的发布部分提供了多个使用此 MsvcLibX 库的程序,这些程序将显示其功能例如:尝试使用我的 which.exe 工具,在 PATH 中使用具有非 ASCII 名称的目录,搜索具有非 ASCII 名称的程序,并更改代码页。

另一个有用的工具是 conv.exe 程序。该程序可以轻松地将数据流从任何代码页转换为任何其他代码页。它默认是在Windows代码页中输入,并在当前控制台代码页中输出。这允许在命令控制台中正确查看 Windows GUI 应用程序(例如:记事本)生成的数据,使用如下简单命令:type WINFILE.txt | conv

这个 MsvcLibX 库并不完整,欢迎贡献改进它!


Dew*_*wfy 5

命令CHCP显示当前代码页.它有三个数字:8xx,与Windows 12xx不同.因此,键入一个只有英文的文本,您将看不到任何差异,但会错误地打印扩展代码页(如Cyrillic).

  • CHCP既不显示3位数也不显示8 ##格式.437例如是美国编码,它是英语系统的事实标准. - 65001是Unicode编码(如果我记得它是正确的,它是UTF-8,65000是UTF-7)并且可以选择.例如,CMD允许切换到1250代码页,但我不知道这些代码页何时可以选择.(它在Win7下.) (5认同)

归档时间:

查看次数:

227997 次

最近记录:

6 年,8 月 前