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

时间:2009-08-11 08:37:00

标签: windows command-line encoding

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

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

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

6 个答案:

答案 0 :(得分:364)

是的,令人沮丧的是 - 有时type和其他程序 打印乱码,有时他们没有。

首先,Unicode字符只显示if the current console font contains the characters。所以使用 一个TrueType字体,如Lucida Console,而不是默认的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 Byte Order Mark (BOM),即字节0xFF 0xFE。 如果它找到这样的 mark,它使用WriteConsoleW在文件中显示Unicode字符 无论当前的代码页如何。但是当type任何文件没有时 UTF-16LE BOM,或用于任何命令的非ASCII字符 不会调用WriteConsoleW - 你需要设置 控制台代码页和程序输出编码相互匹配。


我们怎样才能找到这个?

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

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

这是一个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();
            }
        }
    }
}

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

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}

但是,如果我们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       õ¢áÕÑ¢

唯一的工作原理是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.

由于copy CON无法正确显示Unicode,我们可以 得出结论,type命令具有检测UTF-16LE BOM的逻辑 启动该文件,并使用特殊的Windows API进行打印。

我们可以通过在cmd.exe调试器中打开type来看到这一点 出文件:

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在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程序可以编程为使用输出Unicode到控制台 WriteConsoleW
  • 设置代码页并相应调整其输出编码的其他程序可以在控制台上打印Unicode,无论程序启动时代码页是什么
  • 对于其他一切你将不得不与chcp混乱,并可能仍然会得到奇怪的输出。

答案 1 :(得分:27)

类型

chcp

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

使用

nlsinfo

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

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

答案 2 :(得分:21)

回答你的第二个问题。编码是如何运作的,Joel Spolsky写了一篇很棒的introductory article on this。强烈推荐。

答案 3 :(得分:5)

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

答案 4 :(得分:3)

我长期以来因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路径名&gt; 260个字符,实际上高达64 KB。
  • 相同的源代码可以使用Visual C ++和MsvcLibX以及Visual C ++ C库在Windows中成功编译和链接,在Linux中使用gcc和Linux标准C库,而不需要#ifdef ... #endif blocks。
  • 添加Linux中常见的包含文件,但在Visual C ++中缺少。例如:unistd.h
  • 添加缺少的功能,例如目录I / O,符号链接管理等功能,当然还有UTF-8支持: - )。

MsvcLibX README on GitHub中的更多详细信息,包括如何构建库并在您自己的程序中使用它。

上述GitHub存储库中的release section使用此MsvcLibX库提供了几个程序,这些程序将显示其功能。例如:在PATH中尝试使用带有非ASCII名称的目录的who.exe工具,搜索具有非ASCII名称的程序,以及更改代码页。

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

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

答案 5 :(得分:0)

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