【发布时间】:2011-03-25 04:03:43
【问题描述】:
好吧,我需要找出我在某个目录中找到的哪些文件是 UTF8 编码的,或者是 ANSI 编码的,以更改我稍后决定的其他编码。我的问题是.. 我怎样才能确定文件是 UTF8 还是 ANSI 编码?这两种编码实际上都可以在我的文件中使用。
【问题讨论】:
标签: c#
好吧,我需要找出我在某个目录中找到的哪些文件是 UTF8 编码的,或者是 ANSI 编码的,以更改我稍后决定的其他编码。我的问题是.. 我怎样才能确定文件是 UTF8 还是 ANSI 编码?这两种编码实际上都可以在我的文件中使用。
【问题讨论】:
标签: c#
请看这两篇codeproject文章——单纯从文件内容中找出文件编码并非易事:
【讨论】:
没有可靠的方法来做到这一点(因为文件可能只是随机二进制文件),但是由 Windows 记事本软件完成的过程在 Micheal S Kaplan 的博客中有详细说明:
http://www.siao2.com/2007/04/22/2239345.aspx
- 检查前两个字节; 1. 如果存在 UTF-16 LE BOM,则将其视为(并加载)为“Unicode”文件; 2.如果存在UTF-16 BE BOM,则将其视为(并加载)为“Unicode(Big Endian)”文件; 3. 如果前两个字节看起来像 UTF-8 BOM 的开头,则检查下一个字节,如果我们有 UTF-8 BOM,则将其视为(并加载)为“UTF-8”文件;
- 检查 IsTextUnicode 以查看该函数是否认为它是无 BOM 的 UTF-16 LE,如果是,则将其视为(并加载)为“Unicode”文件;
- 使用 1998 年的原始 RFC 2279 定义检查它是否为 UTF-8,然后将其视为(并加载)为“UTF-8”文件;
- 假设 ANSI 文件使用机器的默认系统代码页。
现在注意有一些漏洞 在这里,就像第 2 步一样 没有 BOM 的情况不太好 UTF-16 BE(甚至可能存在错误 在这里,我不确定——如果是这样,那是一个错误 在记事本中超出任何错误 IsTextUnicode)。
【讨论】:
detectEncodingFromByteOrderMarks 参数传递 true,StreamReader 会自动执行此操作。 msdn.microsoft.com/en-us/library/7bc2hwcb.aspx
ANSI ?
http://msdn.microsoft.com/en-us/netframework/aa569610.aspx#Question2
没有很好的方法来检测 任意 ANSI 代码页,尽管有 已经做了一些尝试 基于某些概率 文本中间的字节序列。 我们不会在 StreamReader 中尝试这样做。一种 很少有像 XML 或 HTML 这样的文件格式 一种指定字符集的方法 在文件的第一行,所以 Web 浏览器、数据库和类,如 XmlTextReader 可以读取这些文件 正确。但是许多文本文件没有 建立这种类型的信息 在。
【讨论】:
Unicode/UTF8/UnicodeBigEndian 被认为是不同的类型。 ANSI 被认为与 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;
}
}
【讨论】:
using statement 而不是手动关闭/处置对象,以确保即使在发生意外异常时也能处置这些对象。
public static System.Text.Encoding GetEncoding(string filepath, Encoding defaultEncoding)
{
// will fall to defaultEncoding if file does not have BOM
using (var reader = new StreamReader(filepath, defaultEncoding, true))
{
reader.Peek(); //need it
return reader.CurrentEncoding;
}
}
要查看 BOM,您需要以十六进制视图查看文件。
记事本在状态栏显示文件编码,但如果文件没有设置BOM,则可以只是估计。
【讨论】: