2010-09-29 14 views
61

Sí es la pregunta más frecuente, y este asunto es impreciso para mí y no sé mucho al respecto.Manera efectiva de encontrar la codificación de cualquier archivo

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

+1

posible duplicado de [Java: Cómo determinar la codificación de juego de caracteres correcto de una corriente ] (http://stackoverflow.com/questions/499010/java-how-to-determine-the-correct-charset-encoding-of-a-stream) – Oded

+0

¿Qué codificaciones? UTF-8 vs UTF-16, grande vs little endian? ¿O se refiere a las viejas páginas de códigos de MSDos, como shift-JIS o cirílico, etc.? – dthorpe

+0

Otro posible duplicado: http://stackoverflow.com/questions/436220/python-is-herehere-a-way-to-determine-the-encoding-of-text-file – Oded

Respuesta

96

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

/// <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) 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 la codificación de la página de códigos ANSI actual del sistema operativo se devuelve por defecto.

+3

+1. Esto funcionó para mí también (mientras que detectEncodingFromByteOrderMarks no lo hizo). Usé "nuevo FileStream (nombre de archivo, FileMode.Open, FileAccess.Read)" para evitar una IOException porque el archivo es de solo lectura. – Polyfun

+1

esta es definitivamente la respuesta correcta, la marcada como correcta no funcionó para mí – sebagomez

+26

Los archivos UTF-8 pueden estar sin BOM, en este caso devolverá ASCII incorrectamente. – user626528

8

que iba a tratar los siguientes pasos:

1) Compruebe si hay una orden de bytes Marcos

2) Compruebe si el archivo es válido UTF8

3) utilizar el local de "ANSI "codepage (ANSI como lo define Microsoft)

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

+0

Esta parece ser la respuesta más correcta, ya que la otra respuesta no funciona para mí. Uno puede hacerlo con File.OpenRead y .Leyendo los primeros pocos bytes del archivo. – user420667

+0

El paso 2 es un montón de trabajo de programación para verificar los patrones de bits, sin embargo. – Nyerguds

+0

@Nyerguds El enfoque lento está tratando de analizarlo como UTF-8 y reiniciar desde el principio cuando se produce un error de decodificación. Un poco feo (excepciones para el flujo de control) y, por supuesto, el análisis debe ser libre de efectos secundarios. – CodesInChaos

29

el siguiente código funciona bien para mí, utilizando la clase StreamReader:

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

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

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

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

+0

Vuelvo lo que estableció como codificación predeterminada. ¿Podría perderme una maldición? – Rama

+1

@DRAM - esto puede suceder si el archivo no tiene BOM –

+0

Gracias @Simon Mourier. No espero que mi pdf/cualquier archivo no haya nacido. Este enlace http://stackoverflow.com/questions/4520184/how-to-detect-the-character-encoding-of-a-text-file puede ser útil para alguien que intenta detectar sin bom. – Rama

1

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

Los siguientes códigos son mis códigos de PowerShell para determinar si algunos archivos cpp o ho ml se encodeding con la norma 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 codificación 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 de UTF-8, encontraremos el especial el carácter aparece, así que intenta leer con Latin-1.En Latin-1, entre \ x7F y \ xAF está vacío, mientras que GB usa completo entre x00-xFF, por lo que si tengo alguno entre los dos, no es Latin-1

El código está escrito en PowerShell, pero lo usa. neto así que es fácil de traducir 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'); 
1

Compruebe esto.

UDE

Se trata de un puerto de Mozilla detector de juego de caracteres universal y se puede utilizar de esta manera ...

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

Debe saber que UDE es GPL – lindexi

+0

Ok, si está preocupado por la licencia, puede usarla. Licenciado como MIT y puede usarlo tanto para software de código abierto como de código cerrado. https://www.nuget.org/packages/SimpleHelpers.FileEncoding/ –

+0

Thx, parece que puede funcionar para mí. – lindexi

Cuestiones relacionadas