Manera efectiva de encontrar la encoding de cualquier archivo

Sí es la pregunta más frecuente, y este asunto es impreciso para mí y no sé mucho al respecto.

Pero me gustaría una forma muy precisa de encontrar una encoding de archivos. Tan preciso como Notepad ++.

La propiedad StreamReader.CurrentEncoding rara vez devuelve la encoding de archivo de texto correcta para mí. He tenido un mayor éxito determinando el endianness de un archivo, mediante el análisis de su marca de orden de bytes (BOM):

 ///  /// 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. ///  /// The text file to analyze. /// The detected encoding. 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; } 

Como nota al margen, es posible que desee modificar la última línea de este método para devolver Encoding.Default lugar, por lo que la encoding de la página de códigos ANSI actual del sistema operativo se devuelve de forma predeterminada.

El siguiente código funciona bien para mí, usando la clase StreamReader :

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

El truco es usar la llamada Peek ; de lo contrario, .NET no ha hecho nada (y no ha leído el preámbulo, la lista de materiales). Por supuesto, si usa cualquier otra llamada ReadXXX antes de verificar la encoding, también funciona.

Si el archivo no tiene BOM, entonces se usará la encoding defaultEncodingIfNoBom . También hay un StreamReader sin este método de sobrecarga (en este caso, la encoding predeterminada (ANSI) se usará como defaultEncodingIfNoBom), pero recomiendo definir lo que usted considera la encoding predeterminada en su contexto.

Lo he probado con éxito con archivos con BOM para UTF8, UTF16 / Unicode (LE & BE) y UTF32 (LE & BE). No funciona para UTF7.

Intentaría los siguientes pasos:

1) Compruebe si hay una marca de orden de bytes

2) Compruebe si el archivo es válido UTF8

3) Use la página de códigos “ANSI” local (ANSI como lo define Microsoft)

El paso 2 funciona porque la mayoría de las secuencias que no son ASCII en páginas de códigos distintas de UTF8 no son UTF8 válidas.

Mira esto.

UDE

Este es un puerto del Detector de Caracteres Universales de Mozilla y puedes usarlo así …

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

Mire aquí para c #

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

Los siguientes códigos son mis códigos Powershell para determinar si algunos archivos cpp o h o ml están codificados con ISO-8859-1 (Latin-1) o UTF-8 sin BOM, si ninguno supone que es GB18030. Soy un chino que trabaja en Francia y MSVC ahorra como Latin-1 en una computadora francesa y guarda como GB en una computadora china, así que esto me ayuda a evitar problemas de encoding cuando los intercambios de archivos fuente entre mi sistema y mis colegas.

El camino es simple, si todos los caracteres están entre x00-x7E, ASCII, UTF-8 y Latin-1 son todos iguales, pero si leo un archivo no ASCII por UTF-8, encontraremos que el carácter especial aparece , intenta leer con Latin-1. En Latin-1, entre \ x7F y \ xAF está vacío, mientras que GB usa lleno entre x00-xFF, así que si tengo alguno entre los dos, no es Latin-1

El código está escrito en PowerShell, pero usa .net por lo que es fácil traducirlo a C # o 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');