如何检测文本文件的字符编码?

我尝试检测在我的文件中使用哪种字符编码。

我试着用这个代码来获得标准的编码

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。

是否有图表显示哪些编码匹配那五个第一个字节?

您不能依赖具有BOM的文件。 UTF-8不需要它。 而非Unicode编码甚至没有BOM。 然而,还有其他方法来检测编码。

UTF-32

BOM是00 00 FE FF(BE)或FF FE 00 00(LE)。

但是即使没有BOM,UTF-32也很容易检测到。 这是因为Unicode代码点范围限制在U + 10FFFF,因此UTF-32单元总是具有00 {0x | 10} xx xx(对于BE)或xx xx {0x | 10} 00(对于LE) 。 如果数据的长度是4的倍数,并且遵循这些模式之一,则可以安全地假定它是UTF-32。 由于在面向字节的编码中稀疏的00字节,误报几乎是不可能的。

US-ASCII

没有BOM,但你不需要一个。 通过在80-FF范围内缺less字节,可以很容易地识别ASCII码。

UTF-8

BOM是EF BB BF。 但是你不能依靠这个。 许多UTF-8文件没有BOM,特别是源自非Windows系统。

但是你可以放心地假设,如果一个文件validation为UTF-8,那么它就是 UTF-8。 误报很less。

具体而言,假设数据不是ASCII,2字节序列的误报率仅为3.9%(1920/49152)。 对于一个7字节的序列,它小于1%。 对于一个12字节的序列,它小于0.1%。 对于一个24字节的序列,它不到百万分之一。

UTF-16

BOM是FE FF(BE)或FF FE(LE)。 请注意,UTF-16LE BOM在UTF-32LE BOM的开始处find,因此请首先检查UTF-32。

可能有没有BOM的UTF-16文件,但是很难检测到它们。 在没有BOM的情况下识别UTF-16的唯一可靠方法是查找代理对(D [8-B] xx D [CF] xx),但非BMP字符很less用于使这种方法切实可行。

XML

如果文件以字节3C 3F 78 6D 6C(即,ASCII字符“<?xml”)开头,则查找encoding=声明。 如果存在,则使用该编码。 如果没有,则假定UTF-8,这是默认的XML编码。

如果您需要支持EBCDIC,请查找等效顺序4C 6F A7 94 93。

一般来说,如果你有一个包含一个编码声明的文件格式,那么查找这个声明,而不是试图猜测编码。

以上都不是

还有其他数百种编码,需要更多的努力来检测。 我build议尝试使用Mozilla的字符集检测器或.NET端口 。

如果你想追求一个“简单”的解决scheme,你可能会发现这个class我放在一起是有用的:

http://www.architectshack.com/TextFileEncodingDetector.ashx

它首先自动执行BOM检测,然后尝试区分不使用BOM的Unicode编码与其他一些默认编码(通常是Windows-1252,错误地标记为.Net中的Encoding.ASCII)。

如上所述,涉及NCharDet或MLang的“较重”的解决scheme可能是更合适的,正如我在这个类的概述页上所注意到的,最好的是尽可能地提供与用户的某种forms的交互,没有100%的检测率可能!

使用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为了切换逻辑取决于它。

是的,这里有一个: http : //en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding 。

你应该阅读这个: 如何检测文本文件的编码/代码页

如果你的文件以字节60,118,56,46和49开始,那么你有一个模棱两可的情况。 它可以是UTF-8(不含BOM)或任何单字节编码,如ASCII,ANSI,ISO-8859-1等

我使用Ude ,它是Mozilla Universal Charset Detector的C#端口。 它很容易使用,并给出了一些非常好的结果。

这里有几个答案,但没有人发布有用的代码。

这里是我的代码,它检测到微软在StreamReader类中的框架4中检测到的所有编码。

显然你必须在打开stream之前立即调用这个函数,然后再从stream中读取其他内容,因为BOM是stream中的第一个字节。

这个函数需要一个可以查找的stream(例如FileStream)。 如果您有一个无法find的stream,则必须编写一个更复杂的代码,返回一个字节缓冲区,其中的字节已经被读取但不是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; }