Да, это самый частый вопрос, и этот вопрос расплывчато для меня, и, поскольку я мало знаю об этом.
Но я бы хотел очень точно найти файлы Encoding. Так точно, как Notepad ++ есть.
Да, это самый частый вопрос, и этот вопрос расплывчато для меня, и, поскольку я мало знаю об этом.
Но я бы хотел очень точно найти файлы Encoding. Так точно, как Notepad ++ есть.
Свойство StreamReader.CurrentEncoding
редко возвращает правильную кодировку текстового файла для меня. У меня был большой успех, определяющий конечность файла, путем анализа его байтовой маркировки (BOM):
/// <summary>
/// Determines a text file encoding by analyzing its byte order mark (BOM).
/// Defaults to ASCII when detection of the text file endianness fails.
/// </summary>
/// <param name="filename">The text file to analyze.</param>
/// <returns>The detected encoding.</returns>
public static Encoding GetEncoding(string filename)
{
// Read the BOM
var bom = new byte[4];
using (var file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
file.Read(bom, 0, 4);
}
// Analyze the BOM
if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) return Encoding.UTF7;
if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) return Encoding.UTF8;
if (bom[0] == 0xff && bom[1] == 0xfe) return Encoding.Unicode; //UTF-16LE
if (bom[0] == 0xfe && bom[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE
if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return Encoding.UTF32;
return Encoding.ASCII;
}
В качестве дополнительной заметки вам может понадобиться изменить последнюю строку этого метода, чтобы вернуть Encoding.Default
вместо этого, поэтому по умолчанию для кодировки текущей кодовой страницы ANSI возвращается.
Следующий код отлично работает для меня, используя класс StreamReader
:
using (var reader = new StreamReader(fileName, defaultEncodingIfNoBom, true))
{
reader.Peek(); // you need this!
var encoding = reader.CurrentEncoding;
}
Трюк заключается в использовании вызова Peek
, иначе .NET ничего не сделал (и он не прочитал преамбулу, спецификацию). Конечно, если вы используете любой другой вызов ReadXXX
перед проверкой кодировки, он тоже работает.
Если в файле нет спецификации, будет использоваться кодировка defaultEncodingIfNoBom
. Существует также StreamReader без этого метода перегрузки (в этом случае кодировка по умолчанию (ANSI) будет использоваться как defaultEncodingIfNoBom), но я рекомендую определить, что вы считаете кодировкой по умолчанию в своем контексте.
Я успешно тестировал файлы с BOM для UTF8, UTF16/Unicode (LE и BE) и UTF32 (LE и BE). Это не работает для UTF7.
Я бы попробовал следующие шаги:
1) Проверьте, есть ли отметка порядка байтов
2) Проверьте, действительно ли файл UTF8
3) Используйте локальную кодовую страницу ANSI (ANSI, как ее определяет Microsoft)
Шаг 2 работает, потому что большинство не ASCII-последовательностей в кодовых файлах, которые UTF8 недействительны UTF8.
Проверь это.
Это порт Mozilla Universal Charset Detector, и вы можете использовать его следующим образом...
public static void Main(String[] args)
{
string filename = args[0];
using (FileStream fs = File.OpenRead(filename)) {
Ude.CharsetDetector cdet = new Ude.CharsetDetector();
cdet.Feed(fs);
cdet.DataEnd();
if (cdet.Charset != null) {
Console.WriteLine("Charset: {0}, confidence: {1}",
cdet.Charset, cdet.Confidence);
} else {
Console.WriteLine("Detection failed.");
}
}
}
Предоставление деталей реализации шагов, предложенных @CodesInChaos:
1) Проверьте, есть ли метка байтового порядка
2) Проверьте, является ли файл действительным UTF8
3) Используйте локальную кодовую страницу "ANSI" (ANSI, как определяет Microsoft)
Шаг 2 работает, потому что большинство не ASCII-последовательностей в кодовых страницах, отличных от UTF8, не являются допустимыми UTF8. fooobar.com/questions/80234/... объясняет тактику более подробно.
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" codepage
public string DetectFileEncoding(Stream fileStream)
{
var Utf8EncodingVerifier = Encoding.GetEncoding("utf-8", new EncoderExceptionFallback(), new DecoderExceptionFallback());
using (var reader = new StreamReader(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 local ANSI
detectedEncoding = "ISO-8859-1";
}
// Rewind the stream
fileStream.Seek(0, SeekOrigin.Begin);
return detectedEncoding;
}
}
[Test]
public void Test1()
{
Stream fs = File.OpenRead(@".\TestData\TextFile_ansi.csv");
var detectedEncoding = DetectFileEncoding(fs);
using (var reader = new StreamReader(fs, Encoding.GetEncoding(detectedEncoding)))
{
// Consume your file
var line = reader.ReadLine();
...
Посмотрите здесь, С#
https://msdn.microsoft.com/en-us/library/system.io.streamreader.currentencoding%28v=vs.110%29.aspx
string path = @"path\to\your\file.ext";
using (StreamReader sr = new StreamReader(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();
}
Следующие коды являются моими кодами Powershell для определения того, кодируются ли некоторые файлы cpp или h или ml с ISO-8859-1 (Latin-1) или UTF-8 без спецификации, если они не предполагают, что это будет GB18030. Я работаю во Франции, и MSVC сохраняет латинский язык 1 на французском компьютере и сохраняет его на ГБ на китайском компьютере, поэтому это помогает мне избежать проблемы с кодированием, когда происходит обмен файлами между моей системой и моими коллегами.
Путь прост, если все символы находятся между x00-x7E, ASCII, UTF-8 и Latin-1 все одинаковы, но если я прочитаю файл без ASCII UTF-8, мы найдем специальный символ показать, поэтому попробуйте прочитать с Latin-1. В латинском-1 между \x7F и\xAF пусто, тогда как GB использует полный промежуток между x00-xFF, поэтому, если у меня есть какой-либо из двух, это не латинский-1
Код написан в PowerShell, но использует .net, поэтому его легко перевести на С# или F #
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach($i in Get-ChildItem .\ -Recurse -include *.cpp,*.h, *.ml) {
$openUTF = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::UTF8)
$contentUTF = $openUTF.ReadToEnd()
[regex]$regex = '�'
$c=$regex.Matches($contentUTF).count
$openUTF.Close()
if ($c -ne 0) {
$openLatin1 = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::GetEncoding('ISO-8859-1'))
$contentLatin1 = $openLatin1.ReadToEnd()
$openLatin1.Close()
[regex]$regex = '[\x7F-\xAF]'
$c=$regex.Matches($contentLatin1).count
if ($c -eq 0) {
[System.IO.File]::WriteAllLines($i, $contentLatin1, $Utf8NoBomEncoding)
$i.FullName
}
else {
$openGB = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::GetEncoding('GB18030'))
$contentGB = $openGB.ReadToEnd()
$openGB.Close()
[System.IO.File]::WriteAllLines($i, $contentGB, $Utf8NoBomEncoding)
$i.FullName
}
}
}
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
Это может быть полезно
string path = @"address/to/the/file.extension";
using (StreamReader sr = new StreamReader(path))
{
Console.WriteLine(sr.CurrentEncoding);
}
.NET не очень полезен, но вы можете попробовать следующий алгоритм:
попробуйте разобрать в разные кодировки
Вот код:
/// <summary>
/// Determines a text file 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 endianness fails.
/// </summary>
/// <param name="filename">The text file to analyze.</param>
/// <returns>The detected encoding or null.</returns>
public static Encoding GetEncoding(string filename)
{
var encodingByBOM = GetEncodingByBOM(filename);
if (encodingByBOM != null)
return encodingByBOM;
// BOM not found :(, so try to parse characters into several encodings
var 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;
return null; // no encoding found
}
/// <summary>
/// Determines a text file encoding by analyzing its byte order mark (BOM)
/// </summary>
/// <param name="filename">The text file to analyze.</param>
/// <returns>The detected encoding.</returns>
private static Encoding GetEncodingByBOM(string filename)
{
// Read the BOM
var byteOrderMark = new byte[4];
using (var file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
file.Read(byteOrderMark, 0, 4);
}
// Analyze the BOM
if (byteOrderMark[0] == 0x2b && byteOrderMark[1] == 0x2f && byteOrderMark[2] == 0x76) return Encoding.UTF7;
if (byteOrderMark[0] == 0xef && byteOrderMark[1] == 0xbb && byteOrderMark[2] == 0xbf) return Encoding.UTF8;
if (byteOrderMark[0] == 0xff && byteOrderMark[1] == 0xfe) return Encoding.Unicode; //UTF-16LE
if (byteOrderMark[0] == 0xfe && byteOrderMark[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE
if (byteOrderMark[0] == 0 && byteOrderMark[1] == 0 && byteOrderMark[2] == 0xfe && byteOrderMark[3] == 0xff) return Encoding.UTF32;
return null; // no BOM found
}
private static Encoding GetEncodingByParsing(string filename, Encoding encoding)
{
var encodingVerifier = Encoding.GetEncoding(encoding.BodyName, new EncoderExceptionFallback(), new DecoderExceptionFallback());
try
{
using (var textReader = new StreamReader(filename, encodingVerifier, detectEncodingFromByteOrderMarks: true))
{
while (!textReader.EndOfStream)
{
textReader.ReadLine(); // in order to increment the stream position
}
// all text parsed ok
return textReader.CurrentEncoding;
}
}
catch (Exception ex) { }
return null; //
}