复习了Sytem.Text下关于编码转换的一些类,回到我们的问题,你也许已经在想,判断完文件编码的类型后,只需要调用相应的GetString()函数就可以解码了。如下:
string DecodedString = "";
switch (EncodingType)
{
case PaTextEncoding.UTF16LittleEndian:
DecodedString = System.Text.Encoding.Unicode.GetString(buffer);
break;
case PaTextEncoding.UTF16BigEndian:
DecodedString = System.Text.Encoding.BigEndianUnicode.GetString(buffer);
break;
case PaTextEncoding.UTF8:
DecodedString = System.Text.Encoding.UTF8.GetString(buffer);
break;
case PaTextEncoding.UTF7:
DecodedString = System.Text.Encoding.UTF7.GetString(buffer);
break;
case PaTextEncoding.Unknown:
throw new Exception("Unkonw Encoding");
break;
}
想法是没错的,但有一个小小的问题,之前我们提到过BOM,不同的编码文件前面几个字节会有不同的BOM标示,这几个字节唯一的作用就是指明编码类型,在解码时应该去掉这几个字节,但问题是,GetString()函数不会自动去掉这几个字节,如果直接把所有的字节数组传给GetString()函数,因为BOM的影响,解码得到的字符串前面几个字是乱码。
DNN里用了一个比较巧妙的办法,首先侦测字节数组的编码方式,之后把所有的字节数组都转换为ASCII编码方式的字节数组,最后通过ASCIIEncoding的GetString()函数得到字符串。因为BOM的影响,转换得到的ASCII字符串前面会有一些”?”字符,查找这些字符并去掉即可。代码如下:
这一部分代码在DNN的DotNetNuke.Modules.Admin.ResourceInstaller命名空间下的PaDnnInstallerBase类里。
GetAsciiString()函数实现转换为ASCII编码,并解码为String
Create two different encodings.
Dim TargetEncoding As Encoding = Encoding.ASCII
Perform the conversion from one encoding to the other.
Dim asciiBytes As Byte() = Encoding.Convert(SourceEncoding, TargetEncoding, Buffer)
Convert the new byte[] into an ascii string.
Dim asciiString As String = System.Text.Encoding.ASCII.GetString(asciiBytes)
Return asciiString
End Function
根据不同的编码方式,传入不同的参数:
Select Case sqlFile.Encoding
Case PaTextEncoding.UTF16LittleEndian
strScript = GetAsciiString(sqlFile.Buffer, System.Text.Encoding.Unicode) 'System.Text.Encoding.Unicode.GetString(sqlFile.Buffer)
Case PaTextEncoding.UTF16BigEndian
strScript = GetAsciiString(sqlFile.Buffer, System.Text.Encoding.BigEndianUnicode) 'System.Text.Encoding.BigEndianUnicode.GetString(sqlFile.Buffer)
Case PaTextEncoding.UTF8
strScript = GetAsciiString(sqlFile.Buffer, System.Text.Encoding.UTF8) 'System.Text.Encoding.UTF8.GetString(sqlFile.Buffer)
Case PaTextEncoding.UTF7
strScript = GetAsciiString(sqlFile.Buffer, System.Text.Encoding.UTF7) 'System.Text.Encoding.UTF7.GetString(sqlFile.Buffer)
Case PaTextEncoding.Unknown
Throw New Exception(String.Format(SQL_UnknownFile, sqlFile.Name))
End Select
This check needs to be included because the unicode Byte Order mark results in an extra character at the start of the file
The extra character - '?' - causes an error with the database.
If strScript.StartsWith("?") Then
strScript = strScript.Substring(1)
End If
最后的一点问题
DNN里这种避免BOM影响解码的方法有一个问题,那就是它把所有的文件都转为ASCII编码,而ASCII编码是不支持双字节的,也就是说如果文件中包含中文,中文在解码后就成为乱码了。具体现象可以参考这个文章;SQL SERVER 2005 EXPRESS与ASP.net出现中文变成问号的奇怪问题。很可能不是通常的utf-8编码问题。
我想解决方案是,把所有的文件都转为UTF编码,针对BOM影响编码的问题,使用UTF8Encoding.GetString(buffer, 3, buffer.length)跳过字节数组的前三个字节。