141 votes

Un moyen efficace de trouver l'encodage de n'importe quel fichier

Oui, c'est une question très fréquente, et ce sujet est vague pour moi et puisque je n'y connais pas grand chose.

Mais je voudrais un moyen très précis de trouver l'encodage d'un fichier. Aussi précis que Notepad++ l'est.

173voto

2Toad Points 1529

Le site StreamReader.CurrentEncoding renvoie rarement l'encodage correct du fichier texte. J'ai eu plus de succès à déterminer l'endianness d'un fichier en analysant sa marque d'ordre des octets (BOM). Si le fichier n'a pas de BOM, cela ne peut pas déterminer l'encodage du fichier.

*MISE À JOUR le 4/08/2020 pour inclure la détection de l'UTF-32LE et renvoyer le codage correct pour l'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>
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 && bom[2] == 0 && bom[3] == 0) return Encoding.UTF32; //UTF-32LE
    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 new 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 ASCII
    return Encoding.ASCII;
}

56voto

Simon Mourier Points 49585

Le code suivant fonctionne bien pour moi, en utilisant l'option StreamReader classe :

  using (var reader = new StreamReader(fileName, defaultEncodingIfNoBom, true))
  {
      reader.Peek(); // you need this!
      var encoding = reader.CurrentEncoding;
  }

L'astuce consiste à utiliser le Peek sinon, .NET n'a rien fait (et il n'a pas lu le préambule, la nomenclature). Bien sûr, si vous utilisez tout autre ReadXXX avant de vérifier l'encodage, cela fonctionne aussi.

Si le fichier n'a pas de nomenclature, alors la fonction defaultEncodingIfNoBom sera utilisé. Il existe également un StreamReader sans cette méthode de surcharge (dans ce cas, l'encodage par défaut (ANSI) sera utilisé comme defaultEncodingIfNoBom), mais je recommande de définir ce que vous considérez comme l'encodage par défaut dans votre contexte.

J'ai testé cela avec succès avec des fichiers dont la nomenclature est UTF8, UTF16/Unicode (LE & BE) et UTF32 (LE & BE). Cela ne fonctionne pas pour UTF7.

14voto

Berthier Lemieux Points 1093

Fournir les détails de la mise en œuvre des étapes proposées par @CodesInChaos :

1) Vérifiez s'il y a une marque d'ordre d'octet.

2) Vérifier si le fichier est valide UTF8

3) Utiliser le codepage local "ANSI" (ANSI tel que défini par Microsoft).

L'étape 2 fonctionne parce que la plupart des séquences non ASCII dans les pages de code autres que UTF8 ne sont pas des UTF8 valides. https://stackoverflow.com/a/4522251/867248 explique cette tactique plus en détail.

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's 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();
        ...

13voto

Regarde ça.

UDE

C'est un portage de Mozilla Universal Charset Detector et vous pouvez l'utiliser comme ceci...

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.");
        }
    }
}

12voto

CodesInChaos Points 60274

J'essaierais les étapes suivantes :

1) Vérifiez s'il y a une marque d'ordre d'octet.

2) Vérifier si le fichier est valide UTF8

3) Utiliser le codepage local "ANSI" (ANSI tel que défini par Microsoft).

L'étape 2 fonctionne parce que la plupart des séquences non ASCII dans les pages de code autres que UTF8 ne sont pas des UTF8 valides.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X