Céd*_*vin 73 c# encoding byte-order-mark character-encoding
我尝试检测我的文件中使用了哪个字符编码.
我尝试使用此代码来获取标准编码
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;
}
Run Code Online (Sandbox Code Playgroud)
我的第五个字节是60,118,56,46和49.
是否有图表显示哪些编码与这五个第一个字节匹配?
dan*_*n04 81
您不能依赖具有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的字符集检测器或它的.NET端口.
如果您排除了UTF编码,并且没有指向不同编码的编码声明或统计检测,则假设ISO-8859-1或密切相关的Windows-1252.(请注意,最新的HTML标准要求将"ISO-8859-1"声明解释为Windows-1252.)作为Windows的英语默认代码页(以及其他流行语言,如西班牙语,葡萄牙语,德语和法语),它是UTF-8以外最常遇到的编码.
如果你想要一个"简单"的解决方案,你可能会发现我把这个课程放在一起很有用:
http://www.architectshack.com/TextFileEncodingDetector.ashx
它首先自动进行BOM检测,然后尝试区分没有BOM的Unicode编码和一些其他默认编码(通常是Windows-1252,在.Net中错误地标记为Encoding.ASCII).
如上所述,涉及NCharDet或MLang的"更重"的解决方案可能更合适,正如我在本课程的概述页面上所述,最好的是尽可能提供与用户的某种形式的交互,因为那里只是是不是100%的检测率!
这里有几个答案,但没有人发布有用的代码。
这是我的代码,用于检测 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;
}
Run Code Online (Sandbox Code Playgroud)
使用StreamReader并指示它为您检测编码:
using (var reader = new System.IO.StreamReader(path, true))
{
var currentEncoding = reader.CurrentEncoding;
}
Run Code Online (Sandbox Code Playgroud)
并使用代码页标识符 https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx ,以便根据它来切换逻辑.