我尝试检测文件中使用的字符编码。
我尝试使用此代码获取标准编码
public static Encoding GetFileEncoding(string srcFile)
{
// *** Use Default of Encoding.Default (Ansi CodePage)
Encoding enc = Encoding.Default;
// *** Detect byte order mark if any - otherwise assume default
byte[] buffer = new byte[5];
FileStream file = new FileStream(srcFile, FileMode.Open);
file.Read(buffer, 0, 5);
file.Close();
if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
enc = Encoding.UTF8;
else if (buffer[0] == 0xfe && buffer[1] == 0xff)
enc = Encoding.Unicode;
else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
enc = Encoding.UTF32;
else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
enc = Encoding.UTF7;
else if (buffer[0] == 0xFE && buffer[1] == 0xFF)
// 1201 unicodeFFFE Unicode (Big-Endian)
enc = Encoding.GetEncoding(1201);
else if (buffer[0] == 0xFF && buffer[1] == 0xFE)
// 1200 utf-16 Unicode
enc = Encoding.GetEncoding(1200);
return enc;
}
我的第五个字节是60,118,56,46和49。
是否有图表显示哪个编码匹配这五个第一个字节?
答案 0 :(得分:78)
您不能依赖具有BOM的文件。 UTF-8不要求它。而非Unicode编码甚至没有BOM。但是,还有其他方法可以检测编码。
BOM为00 00 FE FF(对于BE)或FF FE 00 00(对于LE)。
但即使没有BOM,UTF-32也很容易被发现。这是因为Unicode代码点范围限制为U + 10FFFF,因此UTF-32单元的模式总是为00 {00-10} xx xx(对于BE)或xx xx {00-10} 00(对于LE) 。如果数据的长度是4的倍数,并且遵循其中一种模式,则可以安全地假设它是UTF-32。由于面向字节编码中的00字节很少,因此误报几乎是不可能的。
没有BOM,但您不需要。通过80-FF范围内的字节数不足,可以很容易地识别ASCII。
BOM是EF BB BF。但你不能依赖于此。许多UTF-8文件没有BOM,特别是如果它们来自非Windows系统。
但您可以放心地假设,如果文件验证为UTF-8,则 为UTF-8。误报很少见。
具体而言,假设数据不是ASCII,则2字节序列的误报率仅为3.9%(1920/49152)。对于7字节序列,它小于1%。对于12字节序列,它小于0.1%。对于一个24字节的序列,它不到百万分之一。
BOM是FE FF(对于BE)或FF FE(对于LE)。请注意,UTF-16LE BOM位于UTF-32LE BOM的开头,因此请先检查UTF-32。
如果您碰巧有一个主要由ISO-8859-1字符组成的文件,那么该文件的一半字节为00也将是UTF-16的强烈指示。
否则,识别没有BOM的UTF-16的唯一可靠方法是寻找代理对(D [8-B] xx D [CF] xx),但非BMP字符太少用于制作这种做法很实用。
如果您的文件以字节3C 3F 78 6D 6C开头(即ASCII字符“<?xml”),则查找encoding=
声明。如果存在,则使用该编码。如果不存在,则假设为UTF-8,这是默认的XML编码。
如果您需要支持EBCDIC,也请查找等效序列4C 6F A7 94 93.
通常,如果您的文件格式包含编码声明,那么请查找该声明,而不是尝试猜测编码。
还有数百种其他编码,需要更多的努力来检测。我建议您尝试Mozilla's charset detector或a .NET port of it。
如果您排除了UTF编码,并且没有指向不同编码的编码声明或统计检测,请假设ISO-8859-1或密切相关的Windows-1252。 (请注意,最新的HTML标准要求将“ISO-8859-1”声明解释为Windows-1252。)作为Windows的英语默认代码页(以及其他流行语言,如西班牙语,葡萄牙语) ,德语和法语),这是UTF-8以外最常遇到的编码。
答案 1 :(得分:9)
如果你想要一个“简单”的解决方案,你可能会发现我把这个课程放在一起很有用:
http://www.architectshack.com/TextFileEncodingDetector.ashx
首先自动进行BOM检测,然后尝试区分没有BOM的Unicode编码与其他一些默认编码(通常是Windows-1252,在.Net中错误地标记为Encoding.ASCII)。
如上所述,涉及NCharDet或MLang的“较重”解决方案可能更合适,正如我在本课程的概述页面上所述,最好是尽可能提供与用户的某种形式的交互,因为根本没有100%的检测率!
答案 2 :(得分:5)
使用StreamReader
并指示它为您检测编码:
using (var reader = new System.IO.StreamReader(path, true))
{
var currentEncoding = reader.CurrentEncoding;
}
并使用代码页标识符 https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx 为了根据它来切换逻辑。
答案 3 :(得分:4)
这里有几个答案,但没有人发布有用的代码。
这是我的代码,它检测Microsoft在StreamReader类的Framework 4中检测到的所有编码。
显然,在打开流之前必须立即调用此函数,然后才能从流中读取任何其他内容,因为BOM是流中的第一个字节。
此函数需要可以搜索的Stream(例如FileStream)。如果你有一个无法寻找的Stream,你必须编写一个更复杂的代码,它返回一个Byte缓冲区,其中包含已经读取但不是BOM的字节。
/// <summary>
/// UTF8 : EF BB BF
/// UTF16 BE: FE FF
/// UTF16 LE: FF FE
/// UTF32 BE: 00 00 FE FF
/// UTF32 LE: FF FE 00 00
/// </summary>
public static Encoding DetectEncoding(Stream i_Stream)
{
if (!i_Stream.CanSeek || !i_Stream.CanRead)
throw new Exception("DetectEncoding() requires a seekable and readable Stream");
// Try to read 4 bytes. If the stream is shorter, less bytes will be read.
Byte[] u8_Buf = new Byte[4];
int s32_Count = i_Stream.Read(u8_Buf, 0, 4);
if (s32_Count >= 2)
{
if (u8_Buf[0] == 0xFE && u8_Buf[1] == 0xFF)
{
i_Stream.Position = 2;
return new UnicodeEncoding(true, true);
}
if (u8_Buf[0] == 0xFF && u8_Buf[1] == 0xFE)
{
if (s32_Count >= 4 && u8_Buf[2] == 0 && u8_Buf[3] == 0)
{
i_Stream.Position = 4;
return new UTF32Encoding(false, true);
}
else
{
i_Stream.Position = 2;
return new UnicodeEncoding(false, true);
}
}
if (s32_Count >= 3 && u8_Buf[0] == 0xEF && u8_Buf[1] == 0xBB && u8_Buf[2] == 0xBF)
{
i_Stream.Position = 3;
return Encoding.UTF8;
}
if (s32_Count >= 4 && u8_Buf[0] == 0 && u8_Buf[1] == 0 && u8_Buf[2] == 0xFE && u8_Buf[3] == 0xFF)
{
i_Stream.Position = 4;
return new UTF32Encoding(true, true);
}
}
i_Stream.Position = 0;
return Encoding.Default;
}
答案 4 :(得分:2)
是的,这里有一个:http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding。
答案 5 :(得分:2)
答案 6 :(得分:1)
如果您的文件以字节60,118,56,46和49开头,则您的案例不明确。它可以是UTF-8(无BOM)或任何单字节编码,如ASCII,ANSI,ISO-8859-1等。
答案 7 :(得分:1)
我使用的是Ude,它是Mozilla Universal Charset Detector的C#端口。它易于使用,并提供了一些非常好的结果。