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

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

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

当您以某种编码方式键入文件时会发生什么?有时我得到乱码(不正确的编码使用),有时它的工作。然而,只要我不知道发生了什么,我就不相信任何事情。有人能解释一下吗?

276609 次浏览

为了回答你的第二个问题:编码是如何工作的,Joel Spolsky写了一个很棒的关于此的介绍性文章。强烈推荐。

命令CHCP显示当前代码页。有三位数字:8xx,不同于Windows 12xx。因此,输入纯英语文本不会看到任何区别,但扩展的代码页(如西里尔字母)将被错误地打印出来。

类型

chcp

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

使用

nlsinfo

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

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

是的,这是令人沮丧的-有时type和其他程序 打印胡言乱语,有时他们不会。

首先,Unicode字符将只显示如果 当前控制台字体包含字符。所以使用 使用TrueType字体,如Lucida Console,而不是默认的光栅字体 但是如果控制台字体不包含你想要显示的字符, 你会看到问号而不是胡言乱语。当你出现胡言乱语时,

当程序使用标准的c库I/O函数如printf时,the 程序的输出编码必须匹配控制台的输出编码,或者 你会变得胡言乱语。chcp显示和设置当前代码页。所有 使用标准c库I/O函数的输出被视为

. chcp显示的代码页

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

    程序可以使用chcpGetConsoleOutputCP,并配置自己以该编码输出,或

    你或程序可以使用chcp或设置控制台当前代码页

    . SetConsoleOutputCP匹配程序的默认输出编码
然而,使用Win32 api的程序可以直接编写UTF-16LE字符串 到控制台 WriteConsoleW。 这是在不设置代码页的情况下获得正确输出的唯一方法。和 即使在使用该函数时,如果字符串不是UTF-16LE编码 首先,Win32程序必须将正确的代码页传递给 MultiByteToWideChar。 同样,如果程序的输出被重定向,WriteConsoleW将不起作用;

type有时有效,因为它检查每个文件的开头 a UTF-16LE 字节顺序标记 (BOM),即字节0xFF 0xFE。 如果它找到这样一个 标记时,它使用WriteConsoleW显示文件中的Unicode字符 不管当前的代码页是什么。但是当typeing任何文件没有 UTF-16LE BOM,或用于在任何命令中使用非ascii字符 不调用__abc0——你将需要设置

.控制台编码页和程序输出编码相互匹配

我们怎么才能知道呢?

下面是一个包含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的逻辑

. txt文件的开头,并使用特殊的Windows api打印它 我们可以通过在调试器中打开cmd.exe来查看这一点,当它转到type时 输出文件:

enter image description here

type打开一个文件后,它检查__abc1的BOM -即。,字节 在little-end -中的0xFF 0xFE -如果存在这样的BOM, type将设置一个 内部fOutputUnicode标志。稍后将检查该标志以确定 是否调用WriteConsoleW 但这是让type输出Unicode的唯一方法,而且仅适用于文件 有bom并且是UTF-16LE的。所有其他文件和程序 没有特殊的代码来处理控制台输出,你的文件会 根据当前代码页进行解释,可能会显示为 胡言乱语。< / p >

你可以在你自己的程序中模拟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控制台中使用 默认代码页。< / p >


对于示例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,并且可能仍然会得到奇怪的输出。

长期以来,我一直为Windows代码页问题以及由此引起的C程序可移植性和本地化问题而感到沮丧。之前的文章已经详细描述了这个问题,所以我不打算在这方面添加任何东西。

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

这个库名为MsvcLibX,可以在https://github.com/JFLarvoire/SysToolsLib上获得。主要特点:

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

MsvcLibX README在GitHub上中有更多细节,包括如何构建库并在您自己的程序中使用它。

上面GitHub存储库中的释放部分提供了几个使用MsvcLibX库的程序,这些程序将显示它的功能。例:试试我的which.exe工具,在PATH中使用非ascii名称的目录,搜索具有非ascii名称的程序,并更改代码页。

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

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

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