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

mccptt67  于 2023-01-27  发布在  Windows
关注(0)|答案(7)|浏览(187)

当我在Windows中打开cmd.exe时,它使用的是什么编码?
我怎样才能检查它当前使用的是哪种编码?它是否取决于我的区域设置或者是否有任何环境变量需要检查?
当你用某种编码输入一个文件时会发生什么?有时我会得到乱码(使用了不正确的编码),有时它会工作。然而,只要我不知道发生了什么,我就不相信任何东西。有人能解释吗?

evrscar2

evrscar21#

是的,这是令人沮丧的有时候type和其他程序会打印乱码,有时候则不会。
首先,Unicode字符将只显示if the current console font contains the characters。所以使用像Lucida Console这样的TrueType字体,而不是默认的光栅字体。
但是如果控制台字体不包含你想要显示的字符,你会看到问号而不是乱码,当你看到乱码时,不仅仅是字体设置。
当程序使用标准C-库I/O函数如printf时,程序的输出编码必须与控制台的输出编码匹配,否则会出现乱码。chcp显示并设置当前代码页。所有使用标准C-库I/O函数的输出都被视为chcp显示的代码页。
将程序的输出编码与控制台的输出编码进行匹配可以通过两种不同的方式完成:

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

但是,使用Win32 API的程序可以使用WriteConsoleW将UTF-16LE字符串直接写入控制台。这是在不设置代码页的情况下获得正确输出的唯一方法。即使在使用该函数时,如果字符串不是以UTF-16LE编码开始的,Win32程序也必须将正确的代码页传递给MultiByteToWideChar。此外,如果程序的输出被重定向,WriteConsoleW将不起作用;在那种情况下需要更多的干预。
type有时会工作,因为它会检查每个文件的开头是否有UTF-16LE Byte Order Mark (BOM),即字节0xFF 0xFE。如果它找到这样的标记,它会使用WriteConsoleW显示文件中的Unicode字符,而不管当前代码页是什么。但是当type处理任何没有UTF-16LE BOM的文件时,或者在任何不调用WriteConsoleW的命令中使用非ASCII字符-您需要设置控制台代码页和程序输出编码以使其相互匹配。
我们怎么才能知道呢?
下面是一个包含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输出一个文件时:

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,并可能仍然会得到奇怪的输出。
owfi6suc

owfi6suc2#

类型

chcp

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

nlsinfo

以查看所有安装的代码页并找出代码页编号的含义。
要使用nlsinfo,您需要安装Windows Server 2003资源工具包(适用于Windows XP)。

lsmd5eda

lsmd5eda3#

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

col17t5w

col17t5w4#

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块。
  • Add包括Linux中常见但Visual C++中缺少的文件。例如:unistd.h
  • 添加缺少的函数,如目录I/O、符号链接管理等,当然都支持UTF-8:-)。

MsvcLibX README on GitHub中的更多细节,包括如何构建库并在自己的程序中使用它。
上面GitHub库中的release section提供了几个使用这个MsvcLibX库的程序,这些程序将显示它的功能。尝试使用我的which.exe工具,在PATH中搜索具有非ASCII名称的目录,搜索具有非ASCII名称的程序,并更改代码页。
另一个有用的工具是conv.exe程序。此程序可以轻松地将数据流从任何代码页转换为任何其他代码页。其默认值是在Windows代码页中输入,并在当前控制台代码页中输出。这允许正确查看Windows GUI应用程序生成的数据(例如:记事本),只需使用一个简单的命令,如:type WINFILE.txt | conv
这个MsvcLibX库并不完整,欢迎大家对它进行改进!

webghufk

webghufk5#

命令CHCP显示当前代码页。它有三个数字:8xx和Windows 12xx是不同的。所以键入一个纯英文文本你不会看到任何区别,但一个扩展代码页(如西里尔)将打印错误。

zd287kbt

zd287kbt6#

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

nfg76nw0

nfg76nw07#

只需创建文件%HOMEPATH%\init.cmd,即可控制代码页。
我的说:

@ECHO OFF
CHCP 65001 > nul

相关问题