本文是总结实际项目经验,代码不少是学习别人整合的,效果稳定可靠,有很大参考价值;但是也有不全面的地方,朋友们拿到可以按照自己需要修改。
场景是项目需要在客户端控制台软件和.NET MVC站点间互相传递数据,数据的量比较大,需要对数据进行转化为byte数据,再压缩后发送,接收方需要接收byte数据,再解压缩,还原成数据。
本文既有Web端发送接收数据,也有CS端发送接收数据,内容比较全面。
一、object和byte互转
object和byte互转是基础步骤,实现过程是很简单的,需要用到MemoryStream 、IFormatter 等类。
1、导入命名空间
using System.Collections.Generic; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary;
2、object转byte方法
public static byte[] ToBytes(object obj) { if (obj == null) return null; byte[] buff; using (MemoryStream ms = new MemoryStream()) { IFormatter iFormatter = new BinaryFormatter(); iFormatter.Serialize(ms, obj); buff = ms.GetBuffer(); } return buff; }
3. byte转object
public static object ToObject(byte[] bytes) { if (bytes == null) return null; object obj; using (MemoryStream ms = new MemoryStream(bytes)) { IFormatter iFormatter = new BinaryFormatter(); obj = iFormatter.Deserialize(ms); } return obj; }
二、使用SharpZipLib进行GZip压缩和解压
经过反复实现修改,我感觉用开源类库ICSharpCode.SharpZipLib进行GZip压缩解压比.NET自带的System.IO.Compression.GZipStream效果更好。自己感觉,数据读取成DataTable压缩,不如把DataTable转化为实体类列表进行压缩效果好。
ICSharpCode.SharpZipLib你可以很容易从网络上获取到。
如果发送方对数据进行GZip压缩,接收方必须要对数据进行GZip解压。
1、导入命名空间
using ICSharpCode.SharpZipLib.GZip; using System.IO;
2.GZip压缩
public static byte[] GZipCompress(byte[] data) { byte[] bytes = null; using (MemoryStream o = new MemoryStream()) { using (Stream s = new GZipOutputStream(o)) { s.Write(data, 0, data.Length); s.Flush(); } bytes = o.ToArray(); } return bytes; }
3.GZip解压
private const int BUFFER_LENGTH = 2048; public static byte[] GZipDecompress(byte[] data) { byte[] bytes = null; using (MemoryStream o = new MemoryStream()) { using (MemoryStream ms = new MemoryStream(data)) { using (Stream s = new GZipInputStream(ms)) { s.Flush(); int size = 0; byte[] buffer = new byte[BUFFER_LENGTH]; while ((size = s.Read(buffer, 0, buffer.Length)) > 0) { o.Write(buffer, 0, size); } } } bytes = o.ToArray(); } return bytes; }
三、Controller发送byte和控制台程序接收byte
1.Controller发送byte
在.NET MVC的Controller类中发送数据很简单,用Response进行如下发送就可以了,当然事先要把数据转化成byte,可以压缩也可以不压缩;但是这里的ContentType 内容表明这个数据是经过GZip压缩的。
private void SendBytes(byte[] bytes) { Response.ClearContent(); Response.ContentType = "application/x-zip-compressed";//发送的是gzip格式 Response.BinaryWrite(bytes); Response.End(); }
2.控制台程序接收byte
虽然说是Controller发送byte,其实是控制台程序访问了某个url后Controller才发送数据,因此这里用PostBinary首先进行访问。
public static byte[] PostBinary(string url, string body, CookieContainer cookie) { HttpWebRequest request = CreateRequest(url, body, cookie); HttpWebResponse response = GetResponse(request); byte[] bytes = ReadAllBytes(response); return bytes; }
private static HttpWebRequest CreateRequest(string url, string body, CookieContainer cookie) { Encoding encoding = Encoding.UTF8; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; request.Accept = "text/html, application/xhtml+xml, */*"; request.ContentType = "application/x-www-form-urlencoded"; request.CookieContainer = cookie; byte[] buffer = encoding.GetBytes(body); request.ContentLength = buffer.Length; request.GetRequestStream().Write(buffer, 0, buffer.Length); return request; }
private static HttpWebResponse GetResponse(HttpWebRequest request) { HttpWebResponse response = null; try { response = (HttpWebResponse)request.GetResponse(); } catch (WebException ex) { response = (HttpWebResponse)ex.Response; } return response; }
ReadAllBytes方法要用到MemoryStream 类。
public static byte[] ReadAllBytes(HttpWebResponse response) { Stream responseStream = response.GetResponseStream(); int bufferSize = 2048; MemoryStream ms = new MemoryStream(); byte[] buffer = new byte[bufferSize]; while (true) { int size = responseStream.Read(buffer, 0, bufferSize); if (size == 0) break; ms.Write(buffer, 0, size); } byte[] responseBytes = ms.ToArray(); return responseBytes; }
四、控制台程序发送byte和Controller接收byte
这一部分和上一部分相反。控制台程序发送byte其实和向网站上传文件一样,Controller接收byte其实也和接收上传的文件一样。
1.控制台程序发送byte
这是是用HttpWebRequest给指定url上传文件,文件当然是按byte格式上传的。
public static HttpWebResponse UploadBinary(string url, string dataName, object obj) { byte[] dataBytes = ObjectBinaryHelper.Compress(obj); if (dataBytes == null) dataBytes = new byte[] { }; string boundary = DateTime.Now.Ticks.ToString("x"); HttpWebRequest uploadRequest = (HttpWebRequest)WebRequest.Create(url);//url为上传的地址 uploadRequest.ContentType = "multipart/form-data; boundary=" + boundary; uploadRequest.Method = "POST"; uploadRequest.Accept = "*/*"; uploadRequest.KeepAlive = true; uploadRequest.Headers.Add("Accept-Language", "zh-cn"); uploadRequest.Headers.Add("Accept-Encoding", "gzip, deflate"); uploadRequest.Credentials = System.Net.CredentialCache.DefaultCredentials; //uploadRequest.Headers["Cookie"] = cookie;//上传文件时需要的cookies //创建一个内存流 Stream memStream = new MemoryStream(); boundary = "--" + boundary; //添加上传文件参数格式边界 string paramFormat = boundary + " Content-Disposition: form-data; name="{0}"; {1} "; NameValueCollection param = new NameValueCollection(); param.Add("fname", dataName);//写上参数 foreach (string key in param.Keys) { string formitem = string.Format(paramFormat, key, param[key]); byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem); memStream.Write(formitembytes, 0, formitembytes.Length); } //添加上传文件数据格式边界 string dataFormat = boundary + " Content-Disposition: form-data; name="{0}";filename="{1}" Content-Type:application/octet-stream "; string header = string.Format(dataFormat, dataName, dataName); byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header); memStream.Write(headerbytes, 0, headerbytes.Length); memStream.Write(dataBytes, 0, dataBytes.Length); //添加文件结束边界 byte[] boundarybytes = System.Text.Encoding.UTF8.GetBytes(" " + boundary + " Content-Disposition: form-data; name="Upload" Submit Query " + boundary + "--"); memStream.Write(boundarybytes, 0, boundarybytes.Length); //设置请求长度 uploadRequest.ContentLength = memStream.Length; //获取请求写入流 Stream requestStream = uploadRequest.GetRequestStream(); //将内存流数据读取位置归零 memStream.Position = 0; byte[] tempBuffer = new byte[memStream.Length]; memStream.Read(tempBuffer, 0, tempBuffer.Length); memStream.Close(); //将内存流中的buffer写入到请求写入流 requestStream.Write(tempBuffer, 0, tempBuffer.Length); requestStream.Close(); //获取到上传请求的响应 HttpWebResponse response = GetResponse(uploadRequest); return response; }
2.Controller接收byte
Controller接收byte也等同于接收文件,这里的参数name是文件名称。
protected byte[] GetHttpBinary(string name) { if (this.Request.Files == null || this.Request.Files.Count <= 0) return null; foreach (string key in this.Request.Files.Keys) { if (key == name) { HttpPostedFileBase httpPostedFile = this.Request.Files[key]; int fileContentLength = httpPostedFile.ContentLength; byte[] fileBytes = new byte[fileContentLength]; //创建Stream对象,并指向上传文件 Stream fileStream = httpPostedFile.InputStream; //从当前流中读取字节,读入字节数组中 fileStream.Read(fileBytes, 0, fileContentLength); return fileBytes; } } return null; }