Как определить кодировку символов текстового файла?
Я пытаюсь определить, какая кодировка символов используется в моем файле.
Я пытаюсь с этим кодом получить стандартное кодирование
public static Encoding GetFileEncoding(string srcFile)
{
// *** Use Default of Encoding.Default (Ansi CodePage)
Encoding enc = Encoding.Default;
// *** Detect byte order mark if any - otherwise assume default
byte[] buffer = new byte[5];
FileStream file = new FileStream(srcFile, FileMode.Open);
file.Read(buffer, 0, 5);
file.Close();
if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
enc = Encoding.UTF8;
else if (buffer[0] == 0xfe && buffer[1] == 0xff)
enc = Encoding.Unicode;
else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
enc = Encoding.UTF32;
else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
enc = Encoding.UTF7;
else if (buffer[0] == 0xFE && buffer[1] == 0xFF)
// 1201 unicodeFFFE Unicode (Big-Endian)
enc = Encoding.GetEncoding(1201);
else if (buffer[0] == 0xFF && buffer[1] == 0xFE)
// 1200 utf-16 Unicode
enc = Encoding.GetEncoding(1200);
return enc;
}
Мой пять первых байтов - 60, 118, 56, 46 и 49.
Есть ли диаграмма, которая показывает, какая кодировка соответствует этим пяти первым байтам?
Ответы
Ответ 1
Вы не можете зависеть от файла, имеющего спецификацию. UTF-8 не требует этого. И кодировки, отличные от Unicode, даже не имеют спецификации. Существуют, однако, другие способы обнаружения кодирования.
UTF-32
BOM - 00 00 FE FF (для BE) или FF FE 00 00 (для LE).
Но UTF-32 легко обнаружить даже без спецификации. Это связано с тем, что диапазон кодовой точки Юникода ограничен U + 10FFFF, и, таким образом, единицы UTF-32 всегда имеют шаблон 00 {0x | 10} xx xx (для BE) или xx xx {0x | 10} 00 (для LE), Если данные имеют длину, кратную 4, и следуют одному из этих шаблонов, вы можете смело предположить, что это UTF-32. Ложные срабатывания почти невозможны из-за редкости 00 байтов в байтовом кодировании.
US-ASCII
Нет спецификации, но вам она не нужна. ASCII можно легко идентифицировать по отсутствию байтов в диапазоне 80 FF.
UTF-8
BOM - EF BB BF. Но вы не можете полагаться на это. Многие файлы UTF-8 не имеют спецификации, особенно если они возникли в системах, отличных от Windows.
Но вы можете смело предположить, что если файл проверяется как UTF-8, это UTF-8. Ложные срабатывания встречаются редко.
В частности, учитывая, что данные не являются ASCII, ложная положительная скорость для 2-байтовой последовательности составляет всего 3,9% (1920/49152). Для 7-байтовой последовательности это менее 1%. Для 12-байтовой последовательности она составляет менее 0,1%. Для 24-байтовой последовательности она меньше 1 в миллионе.
UTF-16
BOM - FE FF (для BE) или FF FE (для LE). Обратите внимание, что спецификация UTF-16LE находится в начале спецификации UTF-32LE, поэтому сначала проверьте UTF-32.
Могут быть файлы UTF-16 без спецификации, но было бы очень сложно их обнаружить. Единственный надежный способ распознавания UTF-16 без спецификации - искать суррогатные пары (D [8-B] xx D [CF] xx), но символы, отличные от BMP, слишком редко используются, чтобы сделать этот подход практичным.
XML
Если ваш файл начинается с байтов 3C 3F 78 6D 6C (то есть символов ASCII "<? xml" ), тогда найдите объявление encoding=
. Если присутствует, используйте эту кодировку. Если отсутствует, то предположим, что UTF-8, который является стандартным XML-кодированием.
Если вам необходимо поддерживать EBCDIC, также ищите эквивалентную последовательность 4C 6F A7 94 93.
В общем случае, если у вас есть формат файла, который содержит объявление кодировки, тогда найдите это объявление, а не пытайтесь угадать кодировку.
Ничего из вышеперечисленного
Существуют сотни других кодировок, которые требуют больше усилий для обнаружения. Я рекомендую попробовать детектор charset Mozilla или порт .NET.
Ответ 2
Если вы хотите продолжить "простое" решение, вы можете найти этот класс, который я сочтет полезным:
http://www.architectshack.com/TextFileEncodingDetector.ashx
Сначала он автоматически определяет обнаружение спецификации, а затем пытается различать кодировки Unicode без спецификации, а также другую кодировку по умолчанию (обычно Windows-1252, некорректно обозначенную как Encoding.ASCII в .Net).
Как отмечалось выше, более "более тяжелое" решение с участием NCharDet или MLang может быть более уместным, и, как я отмечаю на обзорной странице этого класса, лучше всего обеспечить некоторую интерактивность с пользователем, если это вообще возможно, потому что нет возможности 100% -ной скорости обнаружения!
Ответ 3
Используйте StreamReader
и направьте его для обнаружения кодировки для вас:
using (var reader = new System.IO.StreamReader(path, true))
{
var currentEncoding = reader.CurrentEncoding;
}
И используйте Идентификаторы кодовой страницы https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx
для переключения логики в зависимости от нее.
Ответ 4
Несколько ответов здесь, но никто не опубликовал полезный код.
Вот мой код, который обнаруживает все кодировки, обнаруженные Microsoft в Framework 4 в классе StreamReader.
Очевидно, вы должны вызвать эту функцию сразу после открытия потока, прежде чем читать что-либо из потока, потому что спецификация - это первые байты в потоке.
Эта функция требует потока, который может искать (например, FileStream). Если у вас есть Stream, который не может найти вас, вы должны написать более сложный код, который возвращает буфер байта с байтами, которые уже были прочитаны, но которые не являются спецификацией.
/// <summary>
/// UTF8 : EF BB BF
/// UTF16 BE: FE FF
/// UTF16 LE: FF FE
/// UTF32 BE: 00 00 FE FF
/// UTF32 LE: FF FE 00 00
/// </summary>
public static Encoding DetectEncoding(Stream i_Stream)
{
if (!i_Stream.CanSeek || !i_Stream.CanRead)
throw new Exception("DetectEncoding() requires a seekable and readable Stream");
// Try to read 4 bytes. If the stream is shorter, less bytes will be read.
Byte[] u8_Buf = new Byte[4];
int s32_Count = i_Stream.Read(u8_Buf, 0, 4);
if (s32_Count >= 2)
{
if (u8_Buf[0] == 0xFE && u8_Buf[1] == 0xFF)
{
i_Stream.Position = 2;
return new UnicodeEncoding(true, true);
}
if (u8_Buf[0] == 0xFF && u8_Buf[1] == 0xFE)
{
if (s32_Count >= 4 && u8_Buf[2] == 0 && u8_Buf[3] == 0)
{
i_Stream.Position = 4;
return new UTF32Encoding(false, true);
}
else
{
i_Stream.Position = 2;
return new UnicodeEncoding(false, true);
}
}
if (s32_Count >= 3 && u8_Buf[0] == 0xEF && u8_Buf[1] == 0xBB && u8_Buf[2] == 0xBF)
{
i_Stream.Position = 3;
return Encoding.UTF8;
}
if (s32_Count >= 4 && u8_Buf[0] == 0 && u8_Buf[1] == 0 && u8_Buf[2] == 0xFE && u8_Buf[3] == 0xFF)
{
i_Stream.Position = 4;
return new UTF32Encoding(true, true);
}
}
i_Stream.Position = 0;
return Encoding.Default;
}
Ответ 5
Да, есть один здесь: http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding.
Ответ 6
Вы должны прочитать следующее: Как я могу определить кодировку/кодовую страницу текстового файла
Ответ 7
Если ваш файл начинается с байтов 60, 118, 56, 46 и 49, тогда у вас есть двусмысленный случай. Это может быть UTF-8 (без спецификации) или любой из однобайтовых кодировок, таких как ASCII, ANSI, ISO-8859-1 и т.д.
Ответ 8
Я использую Ude, который является портом С# универсального детектора Charset Mozilla. Он прост в использовании и дает некоторые действительно хорошие результаты.