Détection automatique de l’encodage d’un fichier
Ceux qui ont déjà dû traiter des fichiers textes et notamment des fichiers CSV, savent déjà de quoi je vais parler, la difficulté pour traiter l’encodage lors de la lecture (qui provoque notamment les fameux caractères bizarres en lieu et place des accents).
La solution consiste à détecter l’encodage utilisé pour écrire le fichier.
Il existe plusieurs méthodes pour détecter celui-ci, je vais vous en présenter deux, qui ont une approche totalement différente mais complémentaire.
Utiliser le BOM
Cette méthode, la plus connue et la moins couteuse, consiste à utiliser le BOM (Byte Order Mark). Ces quelques octets permettent de déterminer l’encodage d’un fichier. Cependant, cette méthode ne se suffit pas à elle-même car dans certains cas le BOM n’est pas présent (par exemple UTF8-sans bom) et ne peux donc être lu.
public static Encoding DetectEncodingWithBom(Stream stream) { // Lecture des 4 bytes du BOM var bom = new byte[4]; var position = stream.Position; // On se positionne au début du stream stream.Seek(0, SeekOrigin.Begin); stream.Read(bom, 0, 4); // On repositionne le stream à la position originale stream.Seek(position, SeekOrigin.Begin); // Analyse de ces 4 bytes if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) { // UTF7 return Encoding.UTF7; } if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) { // UTF8 return Encoding.UTF8; } if (bom[0] == 0xff && bom[1] == 0xfe) { // UTF-16LE return Encoding.Unicode; } if (bom[0] == 0xfe && bom[1] == 0xff) { // UTF-16BE return Encoding.BigEndianUnicode; } if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) { return Encoding.UTF32; } // Aucun encodage connu n'a pu être déterminé par la lecture du BOM return null; }
UDE
UDE (https://github.com/errepi/ude) est un portage C# du projet Mozilla Universal Chartset Detector qui se base sur le contenu du fichier pour déterminer l’encodage. Pour ceux que ça intéresse, voici un article en présentant comment fonctionne cette approche (http://www-archive.mozilla.org/projects/intl/UniversalCharsetDetection.html).
Pour mettre en place UDE dans votre application C#, il faut ajouter le package NuGet UDE.CSharp et utiliser ensuite la classe ChartsetDetector. Vous allez nourrir celle-ci avec les bytes du fichier d’origine jusqu’à ce que la détection de l’encodage soit terminée. Mais attention, cette méthode peut être particulièrement couteuse puisqu’elle peut potentiellement parcourir tout le contenu du fichier afin de déterminer l’encodage utilisé. Son utilisation peut donc avoir un impact non négligeable d’un point de vue performances. Voici un exemple complet :
public static Encoding DeductEncoding(Stream stream) { Encoding detectedEncoding = null; var position = stream.Position; if (stream.Length <= 0) { return detectedEncoding; } // On se positionne au début du stream stream.Seek(0, SeekOrigin.Begin); var detectBuff = new byte[4096]; // Utilisation de ChartsetDetector pour en déduire l'encodage var chartsetDetector = new CharsetDetector(); while (stream.Read(detectBuff, 0, detectBuff.Length) > 0 && !chartsetDetector.IsDone()) { chartsetDetector.Feed(detectBuff, 0, detectBuff.Length); } chartsetDetector.DataEnd(); // Obtention du Chartset déduit var detectedCharset = chartsetDetector.Charset; if (detectedCharset != null) { // Selon le résultat, obtenir l'Encoding associé switch (detectedCharset) { case "UTF-8": detectedEncoding = Encoding.UTF8; break; case "windows-1252": detectedEncoding = Encoding.GetEncoding(1252); break; // Ajouter les autres encodages que la librairie détecte (cf la page Github) // et que vous souhaitez supporter dans votre application } } chartsetDetector.Reset(); // On repositionne le stream à la position originale stream.Seek(position, SeekOrigin.Begin); return detectedEncoding; }
Un prérequis pour les deux méthodes est que le stream d’entrée puisse être “seekable” afin de pouvoir le positionner au début pour effectuer les opérations de détection.
Les deux méthodes combinées permettent d’avoir de bon résultat dans la détection de l’encodage d’un fichier. C’est pourquoi, je vous conseille dans un premier temps d’utiliser la méthode avec le BOM et si celle-ci ne renvoie pas d’encodage, d’utiliser la méthode avec UDE.
Bon code
Commentaires