Эффективный способ найти любой файл Кодирование

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

Но я бы хотел очень точно найти файлы Encoding. Так точно, как Notepad ++ есть.

Ответ 1

Свойство 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 возвращается.

Ответ 2

Следующий код отлично работает для меня, используя класс 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.

Ответ 3

Я бы попробовал следующие шаги:

1) Проверьте, есть ли отметка порядка байтов

2) Проверьте, действительно ли файл UTF8

3) Используйте локальную кодовую страницу ANSI (ANSI, как ее определяет Microsoft)

Шаг 2 работает, потому что большинство не ASCII-последовательностей в кодовых файлах, которые UTF8 недействительны UTF8.

Ответ 4

Проверь это.

УДЭНСКИЙ

Это порт 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.");
        }
    }
}

Ответ 5

Предоставление деталей реализации шагов, предложенных @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();
        ...

Ответ 6

Посмотрите здесь, С#

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();
}

Ответ 7

Следующие коды являются моими кодами 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');

Ответ 8

Это может быть полезно

string path = @"address/to/the/file.extension";

using (StreamReader sr = new StreamReader(path))
{ 
    Console.WriteLine(sr.CurrentEncoding);                        
}

Ответ 9

.NET не очень полезен, но вы можете попробовать следующий алгоритм:

  1. попытаться найти кодировку по BOM (метка порядка байтов)... очень вероятно, что не будет найден
  2. попробуйте разобрать в разные кодировки

    Вот код:

    /// <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;    // 
    }