谈C#中编码Encoding
1.入门C#时经常看到这样的描述:.NET中的String都是Unicode编码。
在入门之后没太看这样的基础书并且多接触一些编码问题后,我的潜意识总觉得String有很多种编码,utf8,unicode,ascii等,并且不认为C#中有gb2312编码。
2.System.Text.Encoding.Default似乎可以解决一切编码,因为我每次用Default.GetString()来读取流中的字符串都成功!所以Default应该是根据字节的编码方式而改变的,比如如果你的字节序是ascii编码,那么Default就是ascii编码。
只到前几天在CSDN的Java社区看到一个编码问题,外加自己的几个小时的实验,终于对编码问题理清了头绪。
简短描述:
.NET中的String确实只有Unicode一种。所以编码格式的字节序列转换成String时最终都是以Unicode表示。
System.Text.Encoding.Default是取系统的当前ANSI代码页的编码(MSDN上抄的),即当前系统的编码。(在我们的机子上一般都是"gb2312")这就是我每次用Default读取文件流都正确,且必须用Default读取才正确的原因----其实用Encoding.GetEncoding("GB2312")也一样。
详细介绍:
在每次进行byte[]-->String(other-->Unicode)和String-->byte[](Unicode-->other)时都会有编码转换。
比如通常的转换都有设置编码的地方,如StreamReader(string path [, System.Text.Encoding encoding]),Response.Charset,这就相当于你告诉系统byte[]是什么编码,这时候.NET用你指定的编码方式去解码,然后转换成Unicode编码方式的String.
也就是说,不管何时,我们所指定的编码都只是指byte[]。
即Encoding.UTF8.GetString(byte[] buffer)是告诉系统buffer的编码是UTF8。
byte[] buf = Encoding.UTF8.GetBytes(string str)是告诉系统返回的buf编码方式是UTF8。
你可能告诉系统一个假的编码方式,或者你没有告诉系统并且byte[]的编码不是用的默认编码,那么系统解码仍然会用指定编码方式进行,在机器看来他仍然解码成功,然后转换成Unicode编码,因为机器只知道0,1字节序,他不知道解码出来的东西是否是混乱的,在他看来一切正常。
但我们去看,就会发现字符串成了一些莫名其妙的符号而没有任何意义,这就是所谓的乱码。
就好比:"you yi ge",本来是拼英"有一个",你却偏偏告诉别人这是英语,别人用英语去拼,就不知道是怎么回事了,就成了乱码,呵呵。
即:字节序是按指定编码方式编码,它有一个特定的编码方式,但它本身是中性的,不含有任何编码信息。
编码方式理论上是独立于语言的,但实际上需要语言去支持。如JAVA中有"GBK"(gb2312扩展)编码,但.NET中没有。你用Encoding.GetEncoding("GBK")会抛异常。
description: 在c#中提供了编码类Encoding,它有四种编码方案:
1、ASCIIEncoding
2、UnicodeEncoding
3、UTF7Encoding
4、UTF8Encoding
另外还有我们所熟悉的GB2312编码,但是它不是Encoding类下的显示类。尽管如此我们仍然可以使用,Encoding encoder = Encoding.GetEncoding("gb2312");
function dispaly(id){ var div=document.getElementById(id); if(div.style.visibility==''visible''){div.style.visibility=''hidden''} else div.style.visibility=''visible'';}
各种编码类型不一定是兼容的,尤其是在有中文的情况下。在解码从文件读取字节数据时,这一点有重要的影响。
例如:用unicode编码方案写入的数据不能使用ASCII或UTF-8编码方案正确的解码。这是因为unicode编码使用两个字节表示每个字符,而其他方案不是这样。
1、首先来看一下编码后的字节数组内容
我们写了以下程序进行验证这一点:
对于这段字符串 string str="测试文本 Test Text" 分别通过GB2312和UTF8对其进行编码,得到以下字节数组:
-------------------------------GB2312-----------------
178 226 202 212 206 196 177 190 32 84 101 115 116 32 84 101 120 116
------------------------------UTF8------------------
230
181 139 232 175 149 230 150 135 230 156 172 32 84 101 115 116 32 84 101 120 116
可以看出对于中文两者编码后的字节是不一样的,对于英文和空格的编码是一样的。
2、两种编码方案保存到文本的情况
对于同一段字符串 string str="测试文本 Test Text" 分别通过GB2312和UTF8对其进行编码,然后分别保存为两个文本文件,代码如下:
private void GetUTF8()
{
Encoding encoder=Encoding.UTF8 ;
byte[] buff = new byte[encoder.GetByteCount(str)] ;
int j = encoder.GetBytes(str,0,str.Length,buff,0) ;
this.textBox1.Text += " -------------------------------UTF8------------------ ";
for(int i=0;i<buff.Length;++i)
{
this.textBox1.Text += " "+buff[i];
}
FileStream fs = File.Create(@"E:WinFormWindowsApplication1WindowsApplication1UTF8.txt");
fs.Write(buff,0,buff.Length) ;
fs.Close();
}
打开记事本都可以正常显示中文,接下来在对文本进行读取显示:
A、用GB2312方案读gb2312写入的文本显示正常
FileStream fs = File.OpenRead(@"E:WinFormWindowsApplication1WindowsApplication1GB2312.txt");
byte[] buff = new byte[(int)fs.Length] ;
fs.Read(buff,0,buff.Length);
Encoding encoder = Encoding.GetEncoding("gb2312");
string str1 = encoder.GetString(buff,0,buff.Length);
this.textBox1.Text = "-------------GB2312 Encode---------------- " + str1 +" ";
B、用Gb2312方案读取Utf8编码写入的文本显示如下:
? Test Text
C、用UTF8读取GB2312写入的文本显示如下:
娴????? Test Text
这正是我们经常遇见的乱码,多少情况都是编码方案不对应。
一般来说我们都采用UTF8进行编码,在网络中传输数据都默认这种方式。