Какие кодировки? UTF-8 против UTF-16, big vs little endian? Или вы имеете в виду старые кодовые страницы MSDos, такие как shift-JIS или кириллица и т. Д.?
StreamReader.CurrentEncodingСвойство редко возвращает правильный текстовый файл , кодирующий для меня. Я добился большего успеха в определении порядка байтов файла, анализируя его метку порядка байтов (BOM). Если у файла нет спецификации, это не может определить кодировку файла.
* ОБНОВЛЕНО 4/08/2020, чтобы включить обнаружение UTF-32LE и вернуть правильную кодировку для UTF-32BE
/// <summary>/// Determines a text file's encoding by analyzing its byte order mark (BOM)./// Defaults to ASCII when detection of the text file's endianness fails./// </summary>/// <param name="filename">The text file to analyze.</param>/// <returns>The detected encoding.</returns>publicstaticEncodingGetEncoding(string filename){// Read the BOMvar bom =newbyte[4];
using (var file =newFileStream(filename,FileMode.Open,FileAccess.Read)){
file.Read(bom,0,4);}// Analyze the BOMif(bom[0]==0x2b&& bom[1]==0x2f&& bom[2]==0x76)returnEncoding.UTF7;if(bom[0]==0xef&& bom[1]==0xbb&& bom[2]==0xbf)returnEncoding.UTF8;if(bom[0]==0xff&& bom[1]==0xfe&& bom[2]==0&& bom[3]==0)returnEncoding.UTF32;//UTF-32LEif(bom[0]==0xff&& bom[1]==0xfe)returnEncoding.Unicode;//UTF-16LEif(bom[0]==0xfe&& bom[1]==0xff)returnEncoding.BigEndianUnicode;//UTF-16BEif(bom[0]==0&& bom[1]==0&& bom[2]==0xfe&& bom[3]==0xff)returnnew UTF32Encoding(true,true);//UTF-32BE// We actually have no idea what the encoding is if we reach this point, so// you may wish to return null instead of defaulting to ASCIIreturnEncoding.ASCII;}
+1. Это сработало и для меня (тогда как detectEncodingFromByteOrderMarks - нет). Я использовал «новый FileStream (имя файла, FileMode.Open, FileAccess.Read)», чтобы избежать исключения IOException, потому что файл доступен только для чтения.
Polyfun
56
Файлы UTF-8 могут быть без спецификации, в этом случае ASCII будет возвращаться некорректно.
user626528
3
Это неверный ответ. Глядя на справочный источник для StreamReader, что реализация того, что все больше людей хотят. Они создают новые кодировки, а не используют существующие Encoding.Unicodeобъекты, поэтому проверки на равенство завершатся ошибкой (что может случиться редко, потому что, например, Encoding.UTF8могут возвращать разные объекты), но он (1) не использует действительно странный формат UTF-7, (2) по умолчанию используется UTF-8, если спецификация не найдена, и (3) можно переопределить, чтобы использовать другую кодировку по умолчанию.
ангар
2
у меня был больший успех с новым StreamReader (имя файла, истина) .CurrentEncoding
Бенуа
4
В коде есть фундаментальная ошибка; когда вы обнаруживаете подпись UTF32 с прямым порядком байтов ( ), вы возвращаете предоставленную системой , которая является кодировкой с прямым порядком байтов (как указано здесь ). А также, как отмечает @Nyerguds, вы все еще не ищете UTF32LE, у которого есть подпись (согласно en.wikipedia.org/wiki/Byte_order_mark ). Как заметил этот пользователь, эта проверка должна происходить до двухбайтовых проверок, поскольку она является подпадающей. 00 00 FE FFEncoding.UTF32FF FE 00 00
Гленн Слейден
44
Следующий код отлично работает для меня с использованием StreamReaderкласса:
using (var reader =newStreamReader(fileName, defaultEncodingIfNoBom,true)){
reader.Peek();// you need this!var encoding = reader.CurrentEncoding;}
Уловка состоит в том, чтобы использовать Peek вызов, иначе .NET ничего не сделал (и не прочитал преамбулу, спецификацию). Конечно, если вы используете любой другой ReadXXXвызов перед проверкой кодировки, он тоже работает.
Если у файла нет спецификации, то defaultEncodingIfNoBom будет использоваться кодировка. Существует также StreamReader без этого метода перегрузки (в этом случае кодировка по умолчанию (ANSI) будет использоваться как defaultEncodingIfNoBom), но я рекомендую определить, что вы считаете кодировкой по умолчанию в вашем контексте.
Я успешно протестировал это с файлами со спецификацией для UTF8, UTF16 / Unicode (LE & BE) и UTF32 (LE & BE). Это не работает для UTF7.
Я возвращаю то, что установлено по умолчанию. Могу ли я что-то упустить?
Ram
1
@DRAM - это может произойти, если у файла нет спецификации
Саймон Мурье,
Спасибо @Simon Mourier. Я не ожидал, что мой pdf / любой файл не будет создан. Эта ссылка stackoverflow.com/questions/4520184/… может быть полезна для тех, кто пытается обнаружить без бомбы.
Ram
1
В PowerShell мне пришлось запустить $ reader.close (), иначе он был заблокирован от записи. foreach($filename in $args) { $reader = [System.IO.StreamReader]::new($filename, [System.Text.Encoding]::default,$true); $peek = $reader.Peek(); $reader.currentencoding | select bodyname,encodingname; $reader.close() }
js2010
1
@SimonMourier: Это не работает, если файл кодируетсяUTF-8 without BOM
Озкан
11
Я бы попробовал следующие шаги:
1) Проверьте, есть ли отметка порядка байтов
2) Убедитесь, что файл действителен UTF8
3) Используйте локальную кодовую страницу "ANSI" (ANSI, как ее определяет Microsoft)
Шаг 2 работает, потому что большинство последовательностей не ASCII в кодовых страницах, кроме UTF8, не являются допустимыми UTF8.
Это кажется более правильным ответом, поскольку другой ответ мне не подходит. Это можно сделать с помощью File.OpenRead и .Read, прочитав первые несколько байтов файла.
user420667
1
Шаг 2 - это целая куча программных работ для проверки битовых шаблонов.
Nyerguds
1
Я не уверен, что декодирование действительно вызывает исключения или просто заменяет нераспознанные последовательности на '?'. В любом случае, я решил написать небольшой класс проверки шаблонов.
Nyerguds
3
Когда вы создаете экземпляр, Utf8Encodingвы можете передать дополнительный параметр, который определяет, следует ли генерировать исключение или вы предпочитаете скрытое повреждение данных.
CodesInChaos
1
Мне нравится этот ответ. Большинство кодировок (например, 99% ваших случаев использования) будут либо UTF-8, либо ANSI (кодовая страница Windows 1252). Вы можете проверить, содержит ли строка заменяющий символ (0xFFFD), чтобы определить, не удалось ли выполнить кодирование.
Хорошо, если вас беспокоит лицензия, вы можете использовать эту. Имеет лицензию MIT, и вы можете использовать ее как для программного обеспечения с открытым, так и с закрытым исходным кодом. nuget.org/packages/SimpleHelpers.FileEncoding
Алексей Агуэро Альба
Лицензия - MPL с опцией GPL. The library is subject to the Mozilla Public License Version 1.1 (the "License"). Alternatively, it may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL").
jbtule
Похоже, что этот форк в настоящее время является наиболее активным и имеет пакет nuget UDE.Netstandard. github.com/yinyue200/ude
jbtule
очень полезная библиотека, справилась с множеством разных и необычных кодировок! танки!
Мшакуров
6
Предоставление деталей реализации шагов, предложенных @CodesInChaos:
1) Проверьте, есть ли отметка порядка байтов
2) Убедитесь, что файл действителен UTF8
3) Используйте локальную кодовую страницу "ANSI" (ANSI, как ее определяет Microsoft)
Шаг 2 работает, потому что большинство последовательностей не ASCII в кодовых страницах, кроме UTF8, не являются допустимыми UTF8. https://stackoverflow.com/a/4522251/867248 объясняет тактику более подробно.
using System; using System.IO; using System.Text;// Using encoding from BOM or UTF8 if no BOM found,// check if the file is valid, by reading all lines// If decoding fails, use the local "ANSI" codepagepublicstringDetectFileEncoding(Stream fileStream){varUtf8EncodingVerifier=Encoding.GetEncoding("utf-8",newEncoderExceptionFallback(),newDecoderExceptionFallback());
using (var reader =newStreamReader(fileStream,Utf8EncodingVerifier,
detectEncodingFromByteOrderMarks:true, leaveOpen:true, bufferSize:1024)){string detectedEncoding;try{while(!reader.EndOfStream){var line = reader.ReadLine();}
detectedEncoding = reader.CurrentEncoding.BodyName;}catch(Exception e){// Failed to decode the file using the BOM/UT8. // Assume it's local ANSI
detectedEncoding ="ISO-8859-1";}// Rewind the stream
fileStream.Seek(0,SeekOrigin.Begin);return detectedEncoding;}}[Test]publicvoidTest1(){Stream fs =File.OpenRead(@".\TestData\TextFile_ansi.csv");var detectedEncoding =DetectFileEncoding(fs);
using (var reader =newStreamReader(fs,Encoding.GetEncoding(detectedEncoding))){// Consume your filevar line = reader.ReadLine();...
Спасибо! Это решило для меня. Но я бы предпочел использовать просто reader.Peek() вместо while (!reader.EndOfStream) { var line = reader.ReadLine(); }
Харисон Сильва
reader.Peek()не читает весь поток. Я обнаружил, что с большими потоками этого Peek()было недостаточно. Я использовал reader.ReadToEndAsync()вместо этого.
Гэри Пендлбери
А что такое Utf8EncodingVerifier?
Питер Мур,
1
@PeterMoore Это кодировка для utf8, var Utf8EncodingVerifier = Encoding.GetEncoding("utf-8", new EncoderExceptionFallback(), new DecoderExceptionFallback());она используется в tryблоке при чтении строки. Если кодировщику не удается проанализировать предоставленный текст (текст не закодирован с помощью utf8), Utf8EncodingVerifier выдаст. Исключение перехватывается, и тогда мы знаем, что текст - это не utf8, а по умолчанию - ISO-8859-1
Бертье Лемье,
2
Следующие коды являются моими кодами Powershell для определения того, кодируются ли некоторые файлы cpp, h или ml с помощью ISO-8859-1 (Latin-1) или UTF-8 без спецификации, если ни то, ни другое, тогда предположите, что это GB18030. Я китаец, работающий во Франции, и MSVC сохраняет как Latin-1 на французском компьютере и сохраняет как GB на китайском компьютере, так что это помогает мне избежать проблем с кодированием при обмене исходными файлами между моей системой и моими коллегами.
Способ прост, если все символы находятся между x00-x7E, ASCII, UTF-8 и Latin-1 все одинаковы, но если я прочитаю файл не ASCII с помощью UTF-8, мы найдем специальный символ , поэтому попробуйте читать с помощью Latin-1. В Latin-1 между \ x7F и \ xAF пусто, в то время как GB использует full между x00-xFF, поэтому, если у меня есть что-то между ними, это не Latin-1
Код написан на PowerShell, но использует .net, поэтому его легко перевести на C # или F #.
.NET не очень полезен, но вы можете попробовать следующий алгоритм:
попробуйте найти кодировку по BOM (метка порядка байтов) ... скорее всего, не найдется
попробуйте разобрать на разные кодировки
Вот призыв:
var encoding =FileHelper.GetEncoding(filePath);if(encoding ==null)thrownewException("The file encoding is not supported. Please choose one of the following encodings: UTF8/UTF7/iso-8859-1");
Вот код:
publicclassFileHelper{/// <summary>/// Determines a text file's encoding by analyzing its byte order mark (BOM) and if not found try parsing into diferent encodings /// Defaults to UTF8 when detection of the text file's endianness fails./// </summary>/// <param name="filename">The text file to analyze.</param>/// <returns>The detected encoding or null.</returns>publicstaticEncodingGetEncoding(string filename){var encodingByBOM =GetEncodingByBOM(filename);if(encodingByBOM !=null)return encodingByBOM;// BOM not found :(, so try to parse characters into several encodingsvar encodingByParsingUTF8 =GetEncodingByParsing(filename,Encoding.UTF8);if(encodingByParsingUTF8 !=null)return encodingByParsingUTF8;var encodingByParsingLatin1 =GetEncodingByParsing(filename,Encoding.GetEncoding("iso-8859-1"));if(encodingByParsingLatin1 !=null)return encodingByParsingLatin1;var encodingByParsingUTF7 =GetEncodingByParsing(filename,Encoding.UTF7);if(encodingByParsingUTF7 !=null)return encodingByParsingUTF7;returnnull;// no encoding found}/// <summary>/// Determines a text file's encoding by analyzing its byte order mark (BOM) /// </summary>/// <param name="filename">The text file to analyze.</param>/// <returns>The detected encoding.</returns>privatestaticEncodingGetEncodingByBOM(string filename){// Read the BOMvar byteOrderMark =newbyte[4];
using (var file =newFileStream(filename,FileMode.Open,FileAccess.Read)){
file.Read(byteOrderMark,0,4);}// Analyze the BOMif(byteOrderMark[0]==0x2b&& byteOrderMark[1]==0x2f&& byteOrderMark[2]==0x76)returnEncoding.UTF7;if(byteOrderMark[0]==0xef&& byteOrderMark[1]==0xbb&& byteOrderMark[2]==0xbf)returnEncoding.UTF8;if(byteOrderMark[0]==0xff&& byteOrderMark[1]==0xfe)returnEncoding.Unicode;//UTF-16LEif(byteOrderMark[0]==0xfe&& byteOrderMark[1]==0xff)returnEncoding.BigEndianUnicode;//UTF-16BEif(byteOrderMark[0]==0&& byteOrderMark[1]==0&& byteOrderMark[2]==0xfe&& byteOrderMark[3]==0xff)returnEncoding.UTF32;returnnull;// no BOM found}privatestaticEncodingGetEncodingByParsing(string filename,Encoding encoding){var encodingVerifier =Encoding.GetEncoding(encoding.BodyName,newEncoderExceptionFallback(),newDecoderExceptionFallback());try{
using (var textReader =newStreamReader(filename, encodingVerifier, detectEncodingFromByteOrderMarks:true)){while(!textReader.EndOfStream){
textReader.ReadLine();// in order to increment the stream position}// all text parsed okreturn textReader.CurrentEncoding;}}catch(Exception ex){}returnnull;// }}
string path =@"path\to\your\file.ext";
using (StreamReader sr =newStreamReader(path,true)){while(sr.Peek()>=0){Console.Write((char)sr.Read());}//Test for the encoding after reading, or at least//after the first read.Console.WriteLine("The encoding used was {0}.", sr.CurrentEncoding);Console.ReadLine();Console.WriteLine();}
Ответы:
StreamReader.CurrentEncoding
Свойство редко возвращает правильный текстовый файл , кодирующий для меня. Я добился большего успеха в определении порядка байтов файла, анализируя его метку порядка байтов (BOM). Если у файла нет спецификации, это не может определить кодировку файла.* ОБНОВЛЕНО 4/08/2020, чтобы включить обнаружение UTF-32LE и вернуть правильную кодировку для UTF-32BE
источник
StreamReader
, что реализация того, что все больше людей хотят. Они создают новые кодировки, а не используют существующиеEncoding.Unicode
объекты, поэтому проверки на равенство завершатся ошибкой (что может случиться редко, потому что, например,Encoding.UTF8
могут возвращать разные объекты), но он (1) не использует действительно странный формат UTF-7, (2) по умолчанию используется UTF-8, если спецификация не найдена, и (3) можно переопределить, чтобы использовать другую кодировку по умолчанию.00 00 FE FF
Encoding.UTF32
FF FE 00 00
Следующий код отлично работает для меня с использованием
StreamReader
класса:Уловка состоит в том, чтобы использовать
Peek
вызов, иначе .NET ничего не сделал (и не прочитал преамбулу, спецификацию). Конечно, если вы используете любой другойReadXXX
вызов перед проверкой кодировки, он тоже работает.Если у файла нет спецификации, то
defaultEncodingIfNoBom
будет использоваться кодировка. Существует также StreamReader без этого метода перегрузки (в этом случае кодировка по умолчанию (ANSI) будет использоваться как defaultEncodingIfNoBom), но я рекомендую определить, что вы считаете кодировкой по умолчанию в вашем контексте.Я успешно протестировал это с файлами со спецификацией для UTF8, UTF16 / Unicode (LE & BE) и UTF32 (LE & BE). Это не работает для UTF7.
источник
foreach($filename in $args) { $reader = [System.IO.StreamReader]::new($filename, [System.Text.Encoding]::default,$true); $peek = $reader.Peek(); $reader.currentencoding | select bodyname,encodingname; $reader.close() }
UTF-8 without BOM
Я бы попробовал следующие шаги:
1) Проверьте, есть ли отметка порядка байтов
2) Убедитесь, что файл действителен UTF8
3) Используйте локальную кодовую страницу "ANSI" (ANSI, как ее определяет Microsoft)
Шаг 2 работает, потому что большинство последовательностей не ASCII в кодовых страницах, кроме UTF8, не являются допустимыми UTF8.
источник
Utf8Encoding
вы можете передать дополнительный параметр, который определяет, следует ли генерировать исключение или вы предпочитаете скрытое повреждение данных.Проверь это.
УДЭНСКИЙ
Это порт Mozilla Universal Charset Detector, и вы можете использовать его вот так ...
источник
The library is subject to the Mozilla Public License Version 1.1 (the "License"). Alternatively, it may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL").
Предоставление деталей реализации шагов, предложенных @CodesInChaos:
1) Проверьте, есть ли отметка порядка байтов
2) Убедитесь, что файл действителен UTF8
3) Используйте локальную кодовую страницу "ANSI" (ANSI, как ее определяет Microsoft)
Шаг 2 работает, потому что большинство последовательностей не ASCII в кодовых страницах, кроме UTF8, не являются допустимыми UTF8. https://stackoverflow.com/a/4522251/867248 объясняет тактику более подробно.
источник
reader.Peek()
вместоwhile (!reader.EndOfStream) { var line = reader.ReadLine(); }
reader.Peek()
не читает весь поток. Я обнаружил, что с большими потоками этогоPeek()
было недостаточно. Я использовалreader.ReadToEndAsync()
вместо этого.var Utf8EncodingVerifier = Encoding.GetEncoding("utf-8", new EncoderExceptionFallback(), new DecoderExceptionFallback());
она используется вtry
блоке при чтении строки. Если кодировщику не удается проанализировать предоставленный текст (текст не закодирован с помощью utf8), Utf8EncodingVerifier выдаст. Исключение перехватывается, и тогда мы знаем, что текст - это не utf8, а по умолчанию - ISO-8859-1Следующие коды являются моими кодами Powershell для определения того, кодируются ли некоторые файлы cpp, h или ml с помощью ISO-8859-1 (Latin-1) или UTF-8 без спецификации, если ни то, ни другое, тогда предположите, что это GB18030. Я китаец, работающий во Франции, и MSVC сохраняет как Latin-1 на французском компьютере и сохраняет как GB на китайском компьютере, так что это помогает мне избежать проблем с кодированием при обмене исходными файлами между моей системой и моими коллегами.
Способ прост, если все символы находятся между x00-x7E, ASCII, UTF-8 и Latin-1 все одинаковы, но если я прочитаю файл не ASCII с помощью UTF-8, мы найдем специальный символ , поэтому попробуйте читать с помощью Latin-1. В Latin-1 между \ x7F и \ xAF пусто, в то время как GB использует full между x00-xFF, поэтому, если у меня есть что-то между ними, это не Latin-1
Код написан на PowerShell, но использует .net, поэтому его легко перевести на C # или F #.
источник
.NET не очень полезен, но вы можете попробовать следующий алгоритм:
Вот призыв:
Вот код:
источник
Ищите здесь С #
https://msdn.microsoft.com/en-us/library/system.io.streamreader.currentencoding%28v=vs.110%29.aspx
источник
Может быть полезно
источник