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.
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.
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;
}
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.
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();
...
Regarde ça.
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.");
}
}
}
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 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.