.NET BS端和CS端相互壓縮傳送接收byte物件資料方法
本文是總結實際專案經驗,程式碼不少是學習別人整合的,效果穩定可靠,有很大參考價值;但是也有不全面的地方,朋友們拿到可以按照自己需要修改。
場景是專案需要在客戶端控制檯軟體和.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 + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}\r\n"; 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 + "\r\nContent-Disposition: form-data; name=\"{0}\";filename=\"{1}\"\r\nContent-Type:application/octet-stream\r\n\r\n"; 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("\r\n\n" + boundary + "\r\nContent-Disposition: form-data; name=\"Upload\"\r\n\nSubmit Query\r\n" + 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; }