Какая кодировка/кодовая страница используется cmd.exe?

Когда я открываю cmd.exe в Windows, какую кодировку он использует?

Как проверить, какая кодировка используется в данный момент? Это зависит от моей региональной настройки или есть ли какие-либо переменные среды для проверки?

Что происходит, когда вы вводите файл с определенной кодировкой? Иногда я получаю искаженные символы (используется некорректная кодировка), и иногда это работает. Однако я ничего не верю, пока не знаю, что происходит. Может кто-нибудь объяснить?

Ответ 1

Да, его разочарование, иногда type и другие программы печатать тарабарщину, а иногда и нет.

Прежде всего, символы Unicode будут отображаться если текущий шрифт консоли содержит символы. Поэтому используйте шрифт TrueType, например Lucida Console, вместо стандартного растрового шрифта.

Но если шрифт консоли не содержит символ, который вы пытаетесь отобразить, вы увидите вопросительные знаки вместо тарабарщины. Когда вы получаете тарабарщину, theres больше происходит, чем просто настройки шрифта.

Когда в программах используются стандартные функции ввода-вывода C-библиотеки, такие как printf, кодирование вывода программ должно соответствовать кодировке вывода консолей или вы получите тарабарщину. chcp показывает и устанавливает текущую кодовую страницу. Все вывод с использованием стандартных функций ввода-вывода C-библиотеки обрабатывается так, как если бы он находился в кодовая страница отображается chcp.

Соответствие программному кодированию вывода с кодировкой вывода консолей может выполняться двумя разными способами:

  • Программа может получить текущую кодовую страницу консоли с помощью chcp или GetConsoleOutputCP и настроить себя для вывода в этой кодировке или

  • Вы или программа можете установить текущую кодовую страницу консоли с помощью chcp или SetConsoleOutputCP, чтобы соответствовать выходной кодировке программы по умолчанию.

Однако программы, использующие API Win32, могут напрямую писать строки UTF-16LE на консоль с WriteConsoleW. Это единственный способ получить правильный вывод без установки кодовых страниц. А также даже при использовании этой функции, если строка не содержится в кодировке UTF-16LE для начала, программа Win32 должна передать правильную кодовую страницу MultiByteToWideChar. Кроме того, WriteConsoleW не будет работать, если выход программ будет перенаправлен; в этом случае необходимо больше возиться.

type работает некоторое время, потому что он проверяет начало каждого файла для UTF-16LE Знак байтового байта (BOM), то есть байты 0xFF 0xFE. Если он найдет такое mark, он отображает символы Unicode в файле с помощью WriteConsoleW независимо от текущей кодовой страницы. Но когда 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 со спецификацией, напечатанный на консоли через 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 на начало файла и использование специальных API Windows для его печати. ​​

Мы видим это, открывая cmd.exe в отладчике, когда он переходит в type из файла:

enter image description here

После type открывается файл, он проверяет спецификацию 0xFEFF -i.e., байты 0xFF 0xFE в little-endian-и если есть такая спецификация, type устанавливает внутренний флаг fOutputUnicode. Этот флаг проверяется позже, чтобы принять решение вызов WriteConsoleW.

Но это единственный способ получить type для вывода Unicode и только для файлов которые имеют спецификации и находятся в 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;
}

Эта программа работает для печати Unicode на консоли Windows, используя кодовая страница по умолчанию.


Для примера программы 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
…

Однако программа C, которая устанавливает кодовую страницу Unicode UTF-8:

#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 может печатать файлы UTF-16LE с спецификацией независимо от текущей кодовой страницы
  • Программы Win32 можно запрограммировать на вывод Unicode на консоль, используя WriteConsoleW.
  • Другие программы, которые устанавливают кодовую страницу и корректируют их выходное кодирование, соответственно могут печатать Unicode на консоли независимо от того, какая кодовая страница была при запуске программы.
  • Для всего остального вам придется возиться с chcp и, вероятно, все равно получите странный результат.

Ответ 2

Тип

chcp

чтобы увидеть вашу текущую страницу кода (как уже сказал Dewfy).

Использование

nlsinfo

чтобы просмотреть все установленные страницы кода и узнать, что означает номер вашей кодовой страницы.

Для использования nlsinfo необходимо установить набор ресурсов Windows Server 2003 (работает в Windows XP).

Ответ 3

Чтобы ответить на второй запрос re. как работает кодирование, Джоэл Спольский написал замечательную вступительную статью об этом. Настоятельно рекомендуется.

Ответ 4

Команда CHCP показывает текущую кодовую страницу. Он имеет три цифры: 8xx и отличается от Windows 12xx. Поэтому, набирая текст на английском языке, вы не увидите никакой разницы, но расширенная кодовая страница (например, кириллица) будет напечатана неправильно.

Ответ 5

Я долгое время разочаровывался в проблемах с кодовой страницей Windows и проблемах переносимости программ и локализации программ, которые они вызывают. В предыдущих сообщениях подробно изложены вопросы, поэтому я не собираюсь ничего добавлять в этом отношении.

Короче говоря, в конце концов я написал свой собственный слой библиотеки совместимости UTF-8 поверх стандартной библиотеки C Visual С++. В основном эта библиотека гарантирует, что стандартная программа на C работает правильно, на любой кодовой странице, используя UTF-8 внутри.

Эта библиотека, называемая MsvcLibX, доступна как открытый источник в https://github.com/JFLarvoire/SysToolsLib. Основные возможности:

  • Источники C, закодированные в UTF-8, с использованием обычных строк char [] C и стандартных API-интерфейсов C.
  • На любой кодовой странице все обрабатывается внутри UTF-8 в вашем коде, включая main() подпрограмму argv [], при этом стандартный ввод и вывод автоматически преобразуются в правильную кодовую страницу.
  • Все функции файла stdio.h поддерживают имена путей UTF-8 > 260 символов, фактически до 64 килобайт.
  • Те же источники могут скомпилировать и установить связь в Windows с использованием библиотек Visual С++ и MsvcLibX и Visual С++ C, а также в Linux с использованием стандартной библиотеки CCC и Linux, без необходимости блокировать #ifdef... #endif.
  • Добавляет включенные файлы, распространенные в Linux, но отсутствующие в Visual С++. Пример: unistd.h
  • Добавляет недостающие функции, например, для ввода/вывода каталогов, управления символическими ссылками и т.д., все с поддержкой UTF-8, конечно: -).

Подробнее в MsvcLibX README на GitHub, в том числе о том, как создать библиотеку и использовать ее в своих собственных программах.

Раздел в приведенном выше репозитории GitHub предоставляет несколько программ, использующих эту библиотеку MsvcLibX, которая покажет свои возможности. Пример. Попробуйте использовать инструмент which.exe с каталогами с именами, отличными от ASCII, в PATH, для поиска программ с именами, отличными от ASCII, и смены кодовых страниц.

Другим полезным инструментом является программа conv.exe. Эта программа может легко конвертировать поток данных с любой кодовой страницы в любую другую. Его значение по умолчанию вводится на кодовой странице Windows и выводится на текущей кодовой странице консоли. Это позволяет корректно просматривать данные, созданные приложениями графического интерфейса Windows (например, "Блокнот" ) в командной консоли, с простой командой: type WINFILE.txt | conv

Эта библиотека MsvcLibX ни в коем случае не является полной, и взносы для ее улучшения приветствуются!

Ответ 6

В Java я использовал кодировку "IBM850" для записи файла. Это решило проблему.