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

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

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

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

Да, это расстраивает – иногда type и другие программы печатают тарабарщину, а иногда и нет.

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

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

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

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

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

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

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

type работает некоторое время, потому что он проверяет начало каждого файла для маркировки байтов UTF-16LE (BOM) , то есть байтов 0xFF 0xFE . Если он находит такой знак, он отображает символы Unicode в файле с помощью WriteConsoleW независимо от текущей кодовой страницы. Но при вводе любого файла без спецификации UTF-16LE или для использования символов, отличных от 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 ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺↓☺z☺|☺D☺B☺ R ussian 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦ CJK `O}Y = bom ■ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺↓☺z☺|☺D☺B☺ R ussian 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦ CJK `O}Y == UTF-16BE = no bom ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣☺↓☺z☺|☺D☺B R ussian ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O CJKO`Y} = bom ■ ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣☺↓☺z☺|☺D☺B R ussian ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O CJKO`Y} == UTF-32LE = no bom ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺ ↓☺ z☺ |☺ D☺ B☺ R ussian 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N ♦ O♦ CJK `O }Y = bom ■ ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺ ↓☺ z☺ |☺ D☺ B☺ R ussian 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N ♦ O♦ CJK `O }Y == UTF-32BE = no bom ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣ ☺↓ ☺z ☺| ☺D ☺B R ussian ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N ♦O CJKO` Y} = bom ■ ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣ ☺↓ ☺z ☺| ☺D ☺B R ussian ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N ♦O CJKO` Y} 

Однако, что, если мы type файлы, которые были сохранены? Они содержат те же самые байты, которые были напечатаны на консоли.

 Z:\andrew\projects\sx\1259084>type *.txt uc-test-UTF-16BE-bom.txt ■ ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣☺↓☺z☺|☺D☺B R ussian ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O CJKO`Y} uc-test-UTF-16BE-nobom.txt ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣☺↓☺z☺|☺D☺B R ussian ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O CJKO`Y} uc-test-UTF-16LE-bom.txt ASCII abcde xyz German äöü ÄÖÜ ß Polish ąęźżńł Russian абвгдеж эюя CJK 你好uc-test-UTF-16LE-nobom.txt ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺↓☺z☺|☺D☺B☺ R ussian 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦ CJK `O}Y uc-test-UTF-32BE-bom.txt ■ ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣ ☺↓ ☺z ☺| ☺D ☺B R ussian ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N ♦O CJKO` Y} uc-test-UTF-32BE-nobom.txt ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣ ☺↓ ☺z ☺| ☺D ☺B R ussian ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N ♦O CJKO` Y} uc-test-UTF-32LE-bom.txt ASCII abcdexyz G erman ä ö ü Ä Ö Ü ß P olish ą ę ź ż ń ł R ussian а б в г д е ж э ю я CJK 你 好uc-test-UTF-32LE-nobom.txt ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺ ↓☺ z☺ |☺ D☺ B☺ R ussian 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N ♦ O♦ CJK `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 ■ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺↓☺z☺|☺D☺B☺ R ussian 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦ CJK `O}Y 1 file(s) copied. 

Из того факта, что copy CON не отображает Unicode правильно, мы можем заключить, что команда type имеет логику для обнаружения спецификации UTF-16LE в начале файла и использует специальные API Windows для ее печати.

Мы можем это увидеть, открыв cmd.exe в отладчике, когда он начнет type файл:

введите описание изображения здесь

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

Но это единственный способ получить type вывода Unicode и только для файлов, имеющих спецификации и находящихся в UTF-16LE. Для всех других файлов и для программ, у которых нет специального кода для обработки вывода на консоль, ваши файлы будут интерпретироваться в соответствии с текущей кодовой страницей и, вероятно, будут отображаться как тарабарщина.

Вы можете эмулировать, как type выводит Unicode на консоль в ваших собственных программах, например:

 #include  #define UNICODE #include  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 ASCII abcdexyz …  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 ASCII abcdexyz …  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 ASCII abcdexyz … 

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

 #include  #include  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 и, вероятно, все равно получите странный результат.

Тип

 chcp 

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

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

 nlsinfo 

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

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

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

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

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

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

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

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

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

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

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

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