字符编码和网页文件
来源:互联网 发布:免费爬虫软件手机版 编辑:程序博客网 时间:2024/05/19 13:57
1:字符编码是怎么回事?
举个例子:一张图片,它可以保存为多种格式:jpg、png、bmp、gif等等。虽然数据格式不同,但它们传递的信息是一样的。同理,字符串(string)是信息,而字符编码就是数据格式。
信息是抽象的,而用来记录信息的数据是具体的。比如你脑子里有个想法,这个想法就是个抽象的东西。虽然它得得确确是存在的,但如果你不把它表达出来,那它事实上等于没有。怎么表达呢?说话或写字,可以用汉语、英语、日语。。。
在C#中,string就是信息,抽像的。string本身是没有编码的。但string对应的byte[]数组必需有编码。这就是信息-数据的特点。信息是抽象的,而数据必需有数据格式。你在程序中有一个string,你想把这个string输出到文件,怎么办呢?请看.net字符串输出函数:
byte[] Encoding.GetEncoding(string charset).GetBytes(string text)
text是信息,charset可以把这个信息保存为不同格式的数据。
反过来:
string Encoding.GetEncoding(string Charset).GetString(byte[] data)
可以根据特定格式数据获得信息
所以:字符编码就是string转byte[]时所用的数据格式。"字符(string)的编码"是个错误概念。"字符数据(byte[])的编码"才是正确的。
再回到图片,不同的图片保存方式有不同的特点。jpg压缩比高省空间,bmp质量最高,png各方面性能较为均衡而且支持透明色。string对应的不同编码格式也各有优缺点。如果要表达汉字,一般情况下gb2312最高效。gbk比gb2312能表达更多汉字。而如果你需要表达多国语言,那么需要采用unicode系列如utf-8。
2:网页文件
很多朋友在下载到网页文件后(html、css或js等),发现里面是乱码。乱码的主要原因就是在由byte[]转string过程中,编码格式不对。咋不对呢?就是string转byte[]用的是A编码,可你在反转时用的却是编码B或C。
下面代码是我项目中的一个类,这个项目是把网页保存成mht格式文件。这个类用来下载网页资源,它里面包含了对编码的判定。需要说明的是:html 文件里面一般都包含编码信息,而css或js文件一般没有。少数情况下下载函数可以返回编码类型,更多情况需要自己判定css或js文件的编码类型。怎么判定呢?utf-8可以通过0xef 0xbb 0xbf头进行判定。其它的就很难判定了,对于不能判定情况,我采用html文件的编码。
using System;using System.Collections.Generic;using System.Windows.Forms;using System.IO;using System.IO.Compression;using System.Net;using System.Net.Cache;using System.Text;using System.Text.RegularExpressions;namespace HtmlShow{ public class DownloadFile { string url; /// <summary> /// 资源路径 /// </summary> public string Url { get { return url; } set { url = value; } } /// <summary> /// 原始字符编码 /// </summary> string originalCharset; public string OriginalCharset { get { return originalCharset; } set { originalCharset = value; } } string charset; /// <summary> /// 字符编码 /// </summary> public string CharSet { get { return charset == null ? originalCharset : charset; } set { charset = value; } } string type; /// <summary> /// 资源的mime类型 /// </summary> public string ContentType { get { return type; } } EncodeType encode = EncodeType.none; /// <summary> /// 数据编码 /// </summary> public EncodeType Encode { get { return encode; } set { encode = value; } } /// <summary> /// 字符串内容 /// </summary> public string Content { get { if (originalCharset != null) { return AdjustCharSet(Encoding.GetEncoding(originalCharset).GetString(data)); } else { string temp = Encoding.Default.GetString(data); Regex reg_charset = new Regex("<meta.+?charset=(?<name>.*?)\".*?>", RegexOptions.IgnoreCase); Match m_charset = reg_charset.Match(temp); if (m_charset.Success) { originalCharset = m_charset.Groups["name"].Value; return AdjustCharSet(Encoding.GetEncoding(originalCharset).GetString(data)); } else { if (data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF) { originalCharset = "utf-8"; return AdjustCharSet(Encoding.UTF8.GetString(data)); } else { originalCharset = Encoding.Default.WebName; return Encoding.Default.GetString(data); } } } } } byte[] data; /// <summary> /// 二进制数据 /// </summary> public byte[] Data { get { switch (encode) { case EncodeType.none: case EncodeType.bit8: byte[] data = Encoding.GetEncoding(charset).GetBytes(Content); if (string.Equals(charset, "utf-8", StringComparison.OrdinalIgnoreCase) && data[0] != 0xEF) { byte[] result = new byte[data.Length + 3]; result[0] = 0xEF; result[1] = 0xBB; result[2] = 0xBF; Buffer.BlockCopy(data, 0, result, 3, data.Length); return result; } else { return data; } case EncodeType.base64: string ss = toBase64(this.data); StringBuilder sb = new StringBuilder(); int start = 0; while (start + 76 < ss.Length) { sb.Append(ss.Substring(start, 76) + "\r\n"); start += 76; } if (start < ss.Length - 1) { sb.Append(ss.Substring(start)); } return System.Text.Encoding.Default.GetBytes(sb.ToString()); default: return Encoding.GetEncoding(charset).GetBytes(Content); ; } } } public DownloadFile(string url) { this.url = url; } public bool Download() { Stream stream1 = null; HttpWebRequest HWR = null; HttpWebResponse HWResp = null; StreamReader reader1 = null; MemoryStream temp = new MemoryStream(); Regex reg_charset = new Regex("<meta.+?charset=(?<name>.*?)\".*?>", RegexOptions.IgnoreCase); try { int Redirect = 0; CookieContainer cc = new CookieContainer(); start: HWR = (HttpWebRequest)WebRequest.Create(Url); HWR.Timeout = 16000; //HWR.ReadWriteTimeout = 10000; HWR.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR " + Environment.Version.ToString() + ")"; HWR.Accept = "*/*"; HWR.KeepAlive = true; HWR.Method = "GET"; HWR.Headers.Add("Accept-Language", "zh-cn,en-us;q=0.5"); HWR.Headers.Add("Accept-Encoding", "gzip, deflate"); HWR.ContentType = "application/x-www-form-urlencoded"; HWR.AllowAutoRedirect = false; HWR.CachePolicy = new RequestCachePolicy(RequestCacheLevel.CacheIfAvailable); HWR.Credentials = CredentialCache.DefaultCredentials; HWR.CookieContainer = cc; HWResp = (HttpWebResponse)HWR.GetResponse(); if ((HWResp.StatusCode == HttpStatusCode.Redirect) || (HWResp.StatusCode == HttpStatusCode.Moved) || (HWResp.StatusCode == HttpStatusCode.MovedPermanently)) { cc.Add(HWResp.Cookies); Url = HWResp.Headers["Location"];// HWResp.ResponseUri.OriginalString; Redirect++; goto start; } if (Redirect > 0) { this.Url = HWResp.ResponseUri.OriginalString; } type = HWResp.ContentType; Regex reg = new Regex("charset=(?<set>[^\"\\s;]+)", RegexOptions.IgnoreCase); Match m = reg.Match(type); if (m.Success) { originalCharset = m.Groups["set"].Value; } stream1 = Decompress(HWResp); long totalDownloadedByte = 0; byte[] by = new byte[1024]; int osize = stream1.Read(by, 0, (int)by.Length); while (osize > 0) { totalDownloadedByte = osize + totalDownloadedByte; temp.Write(by, 0, osize); osize = stream1.Read(by, 0, (int)by.Length); } data = temp.GetBuffer(); return true; } catch (Exception) { return false; } finally { if (reader1 != null) { reader1.Close(); } if (stream1 != null) { stream1.Close(); } if (HWResp != null) { HWResp.Close(); } temp.Close(); } } /// <summary> /// 纠正title标签位于charset标志之前的bug /// </summary> /// <returns></returns> private string AdjustCharSet(string text) { string input = string.Copy(text); Regex reg_charset = new Regex("<meta[^<>]+?charset=(?<name>.*?)\"[^<>]*?>", RegexOptions.IgnoreCase); Match m_charset = reg_charset.Match(input); Regex reg_head = new Regex("<head[^>]*?>", RegexOptions.IgnoreCase); Match m_head = reg_head.Match(input); if (m_head.Success && m_charset.Success) { input = input.Replace(m_charset.Value, ""); input = reg_head.Replace(input, m_head.Value + m_charset.Value); } return input; } /// <summary> /// 将Byte[]转换成Base64编码文本 /// </summary> /// <param name="binBuffer">Byte[]</param> /// <returns></returns> public static string toBase64(byte[] binBuffer) { int base64ArraySize = (int)Math.Ceiling(binBuffer.Length / 3d) * 4; char[] charBuffer = new char[base64ArraySize]; Convert.ToBase64CharArray(binBuffer, 0, binBuffer.Length, charBuffer, 0); string s = new string(charBuffer); return s; } /// GZip解压函数 /// </summary> /// <param name="data"></param> /// <returns></returns> public Stream Decompress(HttpWebResponse HWResp) { Stream stream1 = HWResp.GetResponseStream(); MemoryStream stream = new MemoryStream(); if (string.Equals(HWResp.ContentEncoding, "gzip", StringComparison.OrdinalIgnoreCase)) { using (GZipStream gZipStream = new GZipStream(stream1, CompressionMode.Decompress)) { byte[] bytes = new byte[40960]; int n; while ((n = gZipStream.Read(bytes, 0, bytes.Length)) != 0) { stream.Write(bytes, 0, n); } gZipStream.Close(); } stream.Seek((long)0, SeekOrigin.Begin); return stream; } else { if (string.Equals(HWResp.ContentEncoding, "deflate", StringComparison.OrdinalIgnoreCase)) { using (DeflateStream deflateStream = new DeflateStream(stream1, CompressionMode.Decompress)) { byte[] bytes = new byte[40960]; int n; while ((n = deflateStream.Read(bytes, 0, bytes.Length)) != 0) { stream.Write(bytes, 0, n); } deflateStream.Close(); } stream.Seek((long)0, SeekOrigin.Begin); return stream; } } return stream1; } } public enum EncodeType { bit8, base64, none }}
注:EncodeType是对数据进行再编码,为了便于网络传输,和今天讨论主题无关。
最后:
较真地说:C#中的string其实也是有编码的,因为绝对抽像的东西是不存在的。就像你心里的话,在没由嘴里说出和写到纸上前,它是由你的脑细胞、脑电波构成的。。。。
C#中string虽然对你抽像了,但VisualStudio还是要保存它为具体数据格式的。C#中string采用的是unicode(utf-16)编码。string的编码仅对VisualStudio有用,对用户(程序员)透明。
如何判断css和js文件编码,我至今没有一个完美的解决方案(不知道网络浏览器是怎么判定的),大家有好办法欢迎补充。
- 字符编码和网页文件
- 网页特殊字符编码
- 文件管理器之字符和编码
- 网页和URL内非英语字符的编码方法
- 字符和字符编码
- python 编码笔记,字符编码和读取文件
- 字符编码与网页乱码
- 网页文件的编码
- 文件编码与字符编码
- python读写文件,和设置文件的字符编码
- Base64 文件字符编码
- URL编码和网页编码
- 字符编码 - 字符集和编码
- Python(三)集合、文件操作、字符编码和函数
- Python27 和 IronPython 处理文件读写的字符编码问题
- 深入理解Python中的字符编码、文件处理和函数
- 字符,字节和编码
- 字符,字节和编码
- 百度之星资格赛——C题
- Hibernate包括了23个jar包
- android播放avi文件时有声音无图像
- 算法导论(3版)第5章少量习题的解答
- 深入浅出 双向队列集合 Deque
- 字符编码和网页文件
- 试讨论语法、语义、语用三个平面的区别与联系
- Twig 的 tags学习(中文) 之二
- 百度之星资格赛——D题
- javascript脚本的性能优化
- 百度之星资格赛——E题
- preempt_count详解
- 百度之星资格赛——G题
- java实现文件名,路径,日期,文件大小的统计并存入数据库