find任何文件的编码的有效方法

是的,这是一个最常见的问题,这个问题对我来说是模糊的,因为我对此不甚了解。

但我想要一个非常精确的方式来find一个文件编码。 如记事本+ +一样精确。

StreamReader.CurrentEncoding属性很less为我返回正确的文本文件编码。 通过分析字节顺序标记(BOM),我确定了一个文件的字节顺序,从而取得了更大的成功:

 /// <summary> /// Determines a text file's encoding by analyzing its byte order mark (BOM). /// Defaults to ASCII when detection of the text file's endianness fails. /// </summary> /// <param name="filename">The text file to analyze.</param> /// <returns>The detected encoding.</returns> public static Encoding GetEncoding(string filename) { // Read the BOM var bom = new byte[4]; using (var file = new FileStream(filename, FileMode.Open, FileAccess.Read)) { file.Read(bom, 0, 4); } // Analyze the BOM if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) return Encoding.UTF7; if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) return Encoding.UTF8; if (bom[0] == 0xff && bom[1] == 0xfe) return Encoding.Unicode; //UTF-16LE if (bom[0] == 0xfe && bom[1] == 0xff) return Encoding.BigEndianUnicode; //UTF-16BE if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) return Encoding.UTF32; return Encoding.ASCII; } 

请注意,您可能需要修改此方法的最后一行,以返回Encoding.Default ,因此默认情况下会返回操作系统当前ANSI代码页的编码。

下面的代码适用于我,使用StreamReader类:

  using (var reader = new StreamReader(fileName, defaultEncodingIfNoBom, true)) { reader.Peek(); // you need this! var encoding = reader.CurrentEncoding; } 

诀窍是使用Peek调用,否则,.NET没有做任何事情(它没有读过序言,BOM)。 当然,如果在检查编码之前使用其他ReadXXX调用,它也可以工作。

如果文件没有BOM,那么将使用defaultEncodingIfNoBom编码。 还有一个没有这个重载方法的StreamReader(在这种情况下,默认(ANSI)编码将被用作defaultEncodingIfNoBom),但是我build议在你的上下文中定义你认为默认的编码。

我已经用UTF8,UTF16 / Unicode(LE&BE)和UTF32(LE&BE)的BOM文件成功地进行了testing。 它不适用于UTF7。

我会尝试以下步骤:

1)检查是否有字节顺序标记

2)检查文件是否有效的UTF8

3)使用本地“ANSI”代码页(ANSI定义为Microsoft)

步骤2的工作原理是因为UTF8以外的代码页中的大部分非ASCII序列都不是有效的UTF8。

在这里寻找C#

https://msdn.microsoft.com/en-us/library/system.io.streamreader.currentencoding%28v=vs.110%29.aspx

 string path = @"path\to\your\file.ext"; using (StreamReader sr = new StreamReader(path, true)) { while (sr.Peek() >= 0) { Console.Write((char)sr.Read()); } //Test for the encoding after reading, or at least //after the first read. Console.WriteLine("The encoding used was {0}.", sr.CurrentEncoding); Console.ReadLine(); Console.WriteLine(); } 

下面的代码是我的Powershell代码来确定如果一些cpp或h或ml文件正在用ISO-8859-1(Latin-1)或UTF-8编码没有BOM,如果既不假设它是GB18030。 我是一个在法国工作的中国人,MSVC在法语电脑上保存为Latin-1,在中文电脑上保存为GB,所以这可以帮助我避免在我的系统和我的同事之间进行源文件交换时的编码问题。

方法很简单,如果所有字符都在x00-x7E,ASCII,UTF-8和Latin-1之间都是一样的,但是如果我用UTF-8读取一个非ASCII文件,我们会发现特殊字符 出现,所以试着用Latin-1来阅读。 在拉丁语-1中,\ x7F和\ xAF之间是空的,而GB在x00-xFF之间使用完整的,所以如果我在两者之间有任何的话,它不是Latin-1

代码是用PowerShell编写的,但使用.net,所以很容易被转换成C#或F#

 $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False) foreach($i in Get-ChildItem .\ -Recurse -include *.cpp,*.h, *.ml) { $openUTF = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::UTF8) $contentUTF = $openUTF.ReadToEnd() [regex]$regex = ' ' $c=$regex.Matches($contentUTF).count $openUTF.Close() if ($c -ne 0) { $openLatin1 = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::GetEncoding('ISO-8859-1')) $contentLatin1 = $openLatin1.ReadToEnd() $openLatin1.Close() [regex]$regex = '[\x7F-\xAF]' $c=$regex.Matches($contentLatin1).count if ($c -eq 0) { [System.IO.File]::WriteAllLines($i, $contentLatin1, $Utf8NoBomEncoding) $i.FullName } else { $openGB = New-Object System.IO.StreamReader -ArgumentList ($i, [Text.Encoding]::GetEncoding('GB18030')) $contentGB = $openGB.ReadToEnd() $openGB.Close() [System.IO.File]::WriteAllLines($i, $contentGB, $Utf8NoBomEncoding) $i.FullName } } } Write-Host -NoNewLine 'Press any key to continue...'; $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown'); 

检查这个。

UDE

这是Mozilla Universal Charset Detector的一个端口,你可以像这样使用它…

 public static void Main(String[] args) { string filename = args[0]; using (FileStream fs = File.OpenRead(filename)) { Ude.CharsetDetector cdet = new Ude.CharsetDetector(); cdet.Feed(fs); cdet.DataEnd(); if (cdet.Charset != null) { Console.WriteLine("Charset: {0}, confidence: {1}", cdet.Charset, cdet.Confidence); } else { Console.WriteLine("Detection failed."); } } }