2009-08-11 2 views
228

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

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

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

ответ

318

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

Прежде всего, символы Юникода будут отображаться только if the current console font contains the characters. Поэтому используйте шрифт TrueType, например Lucida Console, вместо стандартного растрового шрифта.

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

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

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

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

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

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

type работает некоторое время, потому что он проверяет начало каждого файла для в кодировке UTF-16LE Byte Order Mark (BOM), т.е. байт 0xFF 0xFE. Если он находит такой знак , он отображает символы Unicode в файле, используя WriteConsoleW независимо от текущей кодовой страницы. Но когда type в любом файле без спецификации UTF-16LE или для использования символов, отличных от ASCII, с любой командой , которая не вызывает WriteConsoleW, вам нужно будет установить кодировку кодовой страницы и код выхода программы , чтобы они соответствовали друг другу.


Как мы можем это найти?

Вот тестовый файл, содержащий символы Юникода:

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 в начале файла и использовать специальные API Windows для его печати.

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

enter image description here

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

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

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

Эй, это должен быть самый подробный ответ, который я когда-либо видел на SO. Дополнительный кредит на рассыпные отпечатки и многоязычные навыки! Просто красиво, сэр! –

+2

Можно также изучить расширение _setmode для Microsoft (_fileno (stdout), _O_U16TEXT), которое было представлено в VS2008. См. Http://stackoverflow.com/a/9051543 и http://stackoverflow.com/a/12015918 и http://msdn.microsoft.com/en-us/library/tw4k6df8(v=vs. 90) .aspx Помимо очевидных различий в переносимости между _setmode() и SetConsoleOutputCP(), в обоих подходах могут быть и другие тонкости и побочные эффекты, которые на первый взгляд не полностью понятны. Если andrewdotn может обновить свой ответ с любыми наблюдениями о _setmode (fd, _O_U16TEXT), это было бы здорово. – JasDev

+9

Хотя это отличный ответ, неверно сказать, что консоль поддерживает UTF-16. Он ограничен UCS-2, то есть ограничен символами базовой многоязычной плоскости (BMP). Когда консольный сервер Win32 (conhost.exe, в настоящее время) был спроектирован около 1990 года, Unicode был 16-битным стандартом, поэтому буфер экрана консоли использует одну 16-разрядную WCHAR для ячейки символа. Параметр суррогатной пары UTF-16 печатается как два символа. – eryksun

20

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

+12

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

5

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

+5

CHCP не показывает только 3 цифры или не находится в формате 8 ##. 437 - это, например, американское кодирование, и это стандарт defacto на английских системах. - 65001 - кодировка Unicode (если я правильно назову, UTF-8 и 65000 - UTF-7) и могут быть выбраны. Кроме того, CMD позволяет, например, переключиться на 1250 кодовую страницу, но я не знаю, когда эти кодовые страницы можно выбрать. (Это находится под Win7.) –

21

Тип

chcp 

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

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

nlsinfo 

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

Необходимо установить комплект ресурсов Windows Server 2003 (работает на Windows   XP), чтобы использовать nlsinfo.

+14

Интересно, что 'nlsinfo', похоже, не существует на моей Windows 7. – Joey

+2

' nlsinfo' также не существует на моем компьютере под управлением Windows XP SP3. –

+2

О, извините. Я думаю, что он поставляется с инструментами Windows Server Resource Kit. Я использовал его несколько раз на моем компьютере под управлением Windows XP SP3 раньше и не знал, что он не был установлен по умолчанию. –

1

Я долгое время разочаровывался в проблемах с кодовой страницей 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> 260 символов, на самом деле до 64 Кбайт.
  • Те же источники могут скомпилировать и связать успешную работу в Windows с использованием библиотек Visual C++ и MsvcLibX и Visual C++ C, а также в Linux с использованием стандартной библиотеки CCC и Linux, без необходимости блокировать #ifdef ... #endif.
  • Добавляет файлы, распространенные в Linux, но отсутствующие в Visual C++. Пример: unistd.h
  • Добавляет недостающие функции, например, для ввода-вывода каталога, управления символическими ссылками и т. Д., Все с поддержкой UTF-8, конечно :-).

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

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

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

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

Смежные вопросы