2010-08-04 48 views
13

Bueno, tengo que averiguar cuál de los archivos que encontré en algún directorio es UTF8 codificado, ya sea ANSI codificado para cambiar la codificación en otra cosa que decida más adelante. Mi problema es ... ¿cómo puedo averiguar si un archivo está codificado en UTF8 o ANSI? Ambas codificaciones son realmente posibles en mis archivos.¿Cómo encontrar la codificación de un archivo? C#

Respuesta

12

No hay manera confiable para hacerlo (dado que el archivo puede ser simplemente binario al azar), sin embargo, el proceso realizado por el software del Bloc de notas de Windows se detalla en el blog de Micheal S Kaplan:

http://www.siao2.com/2007/04/22/2239345.aspx

  1. Compruebe los dos primeros bytes; 1. Si hay una BOM de UTF-16 LE, trátela (y cárguela) como un archivo "Unicode"; 2. Si hay una BOM BE de UTF-16, trátela (y cárguela) como un archivo "Unicode (Big Endian)"; 3. Si los dos primeros bytes se ven como el inicio de una BOM UTF-8, luego verifique el siguiente byte y si tenemos una BOM UTF-8, luego trátela (y cárguela) como un archivo "UTF-8" ;
  2. Consulte con IsTextUnicode para ver si esa función cree que es BOM-less UTF-16 LE, de ser así, luego trátela (y cárguela) como un archivo "Unicode";
  3. Compruebe si es UTF-8 usando la definición RFC 2279 original de 1998 y si luego lo trata (y lo carga) como un archivo "UTF-8";
  4. Suponga un archivo ANSI utilizando la página de códigos del sistema predeterminada de la máquina.

Ahora tenga en cuenta que hay algunos agujeros aquí, al igual que el hecho de que el paso 2 no no lo hacen tan bien con lista de materiales a menos UTF-16 BE (incluso puede haber un error aquí, yo' No estoy seguro - si es así, es un error en el Bloc de notas más allá de cualquier error en IsTextUnicode).

+7

StreamReader lo hace automáticamente si pasa 'true' para el parámetro' detectEncodingFromByteOrderMarks'. http://msdn.microsoft.com/en-us/library/7bc2hwcb.aspx – dtb

+0

Gracias, no sabía .net tenía soporte interno para este procedimiento. – sukru

+0

En mis pruebas, los indicadores'detendingEncodingFromByteOrderMarks' no detectan la codificación ANSI – Bertvan

4

http://msdn.microsoft.com/en-us/netframework/aa569610.aspx#Question2

no hay una gran manera de detectar una página de códigos ANSI arbitraria , aunque hay ha habido algunos intentos de hacer esto basado en la probabilidad de ciertos secuencias de bytes en el medio de texto. No probamos eso en StreamReader. A pocos formatos de archivo como XML o HTML tienen una forma de especificar el conjunto de caracteres en la primera línea en el archivo, por lo que los navegadores Web , bases de datos y las clases como XMLTextReader pueden leer correctamente estos archivos . Sin embargo, muchos archivos de texto no han este tipo de información integrada en .

1

Unicode/UTF8/UnicodeBigEndian se consideran diferentes tipos. ANSI se considera lo mismo que UTF8.

public class EncodingType 
{ 
    public static System.Text.Encoding GetType(string FILE_NAME) 
    { 
     FileStream fs = new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read); 
     Encoding r = GetType(fs); 
     fs.Close(); 
     return r; 
    } 

    public static System.Text.Encoding GetType(FileStream fs) 
    { 
     byte[] Unicode = new byte[] { 0xFF, 0xFE, 0x41 }; 
     byte[] UnicodeBIG = new byte[] { 0xFE, 0xFF, 0x00 }; 
     byte[] UTF8 = new byte[] { 0xEF, 0xBB, 0xBF }; //with BOM 
     Encoding reVal = Encoding.Default; 

     BinaryReader r = new BinaryReader(fs, System.Text.Encoding.Default); 
     int i; 
     int.TryParse(fs.Length.ToString(), out i); 
     byte[] ss = r.ReadBytes(i); 
     if (IsUTF8Bytes(ss) || (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF)) 
     { 
      reVal = Encoding.UTF8; 
     } 
     else if (ss[0] == 0xFE && ss[1] == 0xFF && ss[2] == 0x00) 
     { 
      reVal = Encoding.BigEndianUnicode; 
     } 
     else if (ss[0] == 0xFF && ss[1] == 0xFE && ss[2] == 0x41) 
     { 
      reVal = Encoding.Unicode; 
     } 
     r.Close(); 
     return reVal; 

    } 

    private static bool IsUTF8Bytes(byte[] data) 
    { 
     int charByteCounter = 1;  
     byte curByte; 
     for (int i = 0; i < data.Length; i++) 
     { 
      curByte = data[i]; 
      if (charByteCounter == 1) 
      { 
       if (curByte >= 0x80) 
       { 
        while (((curByte <<= 1) & 0x80) != 0) 
        { 
         charByteCounter++; 
        } 
          
        if (charByteCounter == 1 || charByteCounter > 6) 
        { 
         return false; 
        } 
       } 
      } 
      else 
      { 
       if ((curByte & 0xC0) != 0x80) 
       { 
        return false; 
       } 
       charByteCounter--; 
      } 
     } 
     if (charByteCounter > 1) 
     { 
      throw new Exception("Error byte format"); 
     } 
     return true; 
    } 

} 
+0

Parece un gran código. Sin embargo, ¿no se supone que UTF16 LE y UTF16-BE tienen la firma "FF FE" y "FE FF", respectivamente? Has agregado un byte extra. Ver: http://www.unicode.org/faq/utf_bom.html#bom4 –

+0

Por cierto, ¿cómo se compara su función IsUTF8Bytes() con la respuesta de Christoph que se muestra aquí: http://stackoverflow.com/a/1031773/ 848344 –

+0

@DanW: No sé de dónde viene la respuesta de Christoph, el código que publiqué es parte del proyecto que he trabajado, escrito por un compañero de equipo. –

Cuestiones relacionadas