Solución:
No hay una forma confiable de hacerlo (ya que el archivo puede ser simplemente binario aleatorio), sin embargo, el proceso realizado por el software Bloc de notas de Windows se detalla en el blog de Micheal S Kaplan:
http://www.siao2.com/2007/04/22/2239345.aspx
- Verifique los dos primeros bytes; 1. Si hay una lista de materiales UTF-16 LE, trátela (y cárguela) como un archivo “Unicode”; 2. Si hay un BE BOM UTF-16, trátelo (y cárguelo) como un archivo “Unicode (Big Endian)”; 3. Si los primeros dos bytes parecen el inicio de una BOM UTF-8, entonces verifique el siguiente byte y si tenemos una BOM UTF-8, trátelo (y cárguelo) como un archivo “UTF-8”;
- Consulte con IsTextUnicode para ver si esa función cree que es UTF-16 LE sin BOM, si es así, trátelo (y cárguelo) como un archivo “Unicode”;
- Verifique si es UTF-8 usando la definición RFC 2279 original de 1998 y si luego trátelo (y cárguelo) como un archivo “UTF-8”;
- 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í, como el hecho de que el paso 2 no funciona tan bien con UTF-16 BE sin BOM (incluso puede haber un error aquí, no estoy seguro, si es así es un error en el Bloc de notas más allá de cualquier error en IsTextUnicode).
http://msdn.microsoft.com/en-us/netframework/aa569610.aspx#Question2
No existe una buena manera de detectar una página de códigos ANSI arbitraria, aunque ha habido algunos intentos de hacerlo en función de la probabilidad de ciertas secuencias de bytes en medio del texto. No intentamos eso en StreamReader. Algunos formatos de archivo como XML o HTML tienen una forma de especificar el juego de caracteres en la primera línea del archivo, por lo que los navegadores web, las bases de datos y las clases como XmlTextReader pueden leer estos archivos correctamente. Pero muchos archivos de texto no tienen este tipo de información incorporada.
Unicode / UTF8 / UnicodeBigEndian se consideran tipos diferentes. 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;
}
}