C# DataSet 압축
DataSet, DataTable(이하 DataSet으로만 언급하겠지만 DataTable도 같은 사항이다)을 무척이나 많은 용도로 사용하고 있다. DB 리턴값으로 사용하고 네트워크로 통해 넘겨서 클라이언트에서 사용할 수 있도록 한다.
그렇지만 많의 양의 DataSet을 옮기는 가운데 Loading time이 발생하게 된다. 더군다나 네트워크를 통해서 데이타를 보낼때에 더 심각한 UI 멈춤 현상이 발생 할 수도 있다. 그렇지만 네트워크로 조금이라도 압축된 상태로 줄어 들어 넘어 온다면 리드타임을 줄이는 도움이 돌 것으로 기대하며 Dataset압축에 대해서 알아보자.
아래는 DataSet 압축과 압축해제에 관한 소스 전체이다.
/// <summary> /// DataSet 압축 /// </summary> /// <param name="ds">압축할 DataSet</param> /// <param name="remortingFormat">SerializationFormat 종류 default : Binary</param> /// <returns>string으로 변환해서 반환 한다.</returns> /// <remarks> /// DataSet에 대해서 압축 한다. /// 네트워크 동신에서 많은 양을 압축하여 보낼 때 사용 하면 된다. /// </remarks> /// <example> /// <code> DataSet 압축 /// CompressDataSet(DataSet); /// </code> /// </example> /// <exception cref="InvalidCastException"> /// </exception> /// <exception cref="ArgumentException"> /// </exception> public string CompressDataSet(DataSet ds, SerializationFormat remortingFormat = SerializationFormat.Binary) { var compressedByte = CompressDataSetBytes(ds, remortingFormat); return Convert.ToBase64String(compressedByte); } /// <summary> /// DataSet 압축 /// </summary> /// <param name="ds">압축할 DataSet</param> /// <param name="remortingFormat">SerializationFormat 종류 default : Binary</param> /// <returns>byte[] 변환해서 반환 한다.</returns> /// <remarks> /// DataSet에 대해서 압축 한다. /// 네트워크 동신에서 많은 양을 압축하여 보낼 때 사용 하면 된다. /// </remarks> /// <example> /// <code> DataSet을 압축한다. /// CompressDataSet(DataSet); /// </code> /// </example> /// <exception cref="InvalidCastException"> /// </exception> /// <exception cref="ArgumentException"> /// </exception> public byte[] CompressDataSetBytes(DataSet ds, SerializationFormat remortingFormat = SerializationFormat.Binary) { #region Serialize ds.RemotingFormat = remortingFormat; BinaryFormatter bf = new BinaryFormatter(); byte[] inSerializeByte = null; using (MemoryStream ms = new MemoryStream()) { bf.Serialize(ms, ds); inSerializeByte = ms.ToArray(); } #endregion byte[] outPut = BytesCompress(inSerializeByte); return outPut; } /// <summary> /// byte[]를 압축한다. /// </summary> /// <param name="compressByte">압축할 byte[] 데이타</param> /// <returns>byte[] 압축된 데이타를 반환 한다..</returns> /// <seealso cref="http://msdn.microsoft.com/ko-kr/library/system.io.compression.deflatestream.aspx"/> /// <remarks> /// byte[]를 DeflateStream을 이용해서 압축한다. /// </remarks> /// <example> byte[]를 압축한다. /// <code> /// BytesCompress(byte[] compressByte); /// </code> /// </example> /// <exception cref="InvalidCastException"> /// </exception> /// <exception cref="ArgumentException"> /// </exception> public byte[] BytesCompress(byte[] compressByte) { #region compress byte[] outPut = null; using (MemoryStream outStream = new MemoryStream()) { using (DeflateStream objZS = new DeflateStream(outStream, CompressionMode.Compress)) { objZS.Write(compressByte, 0, compressByte.Length); objZS.Flush(); objZS.Close(); } outPut = outStream.ToArray(); } #endregion return outPut; } /// <summary> /// DataSet을 압축 해제 한다. /// </summary> /// <param name="compressedDsStr">압축 해제할 데이타 string</param> /// <param name="remortingFormat">SerializationFormat 종류 default : Binary</param> /// <returns>압축 해제한 DataSet를 반환 한다.</returns> /// <remarks> /// 이 메소드는 압축된 DataSet의 Byte[] -> string이 입력해야 정상적으로 동작한다. /// </remarks> /// <example> DataSet 압축 해제(string) /// <code> /// byte[] compressedByte = Convert.FromBase64String(compressedDsStr); /// DecompressDataSet(compressedByte, remortingFormat); /// </code> /// </example> /// <exception cref="InvalidCastException"> /// </exception> /// <exception cref="ArgumentException"> /// </exception> public DataSet DecompressDataSet(string compressedDsStr, SerializationFormat remortingFormat = SerializationFormat.Binary) { byte[] compressedByte = Convert.FromBase64String(compressedDsStr); return DecompressDataSet(compressedByte, remortingFormat); } /// <summary> /// DataSet을 압축 해제 한다. /// </summary> /// <param name="compressedBytes">압축 해제할 데이타 DataSet byte[]</param> /// <param name="remortingFormat">SerializationFormat 종류 default : Binary</param> /// <returns>압축 해제한 DataSet를 반환 한다.</returns> /// <seealso cref="http://msdn.microsoft.com/ko-kr/library/system.data.dataset.aspx"/> /// <remarks> /// 이 메소드는 압축된 DataSet의 Byte[]를 입력해야 정상적으로 동작한다. /// </remarks> /// <example> /// <code> 압축된 DataSet의 byte[]를 압축 해제 한다. /// byte[] compressedByte = Convert.FromBase64String(compressedDsStr); /// DecompressDataSet(compressedBytes, remortingFormat); /// </code> /// </example> /// <exception cref="InvalidCastException"> /// </exception> /// <exception cref="ArgumentException"> /// </exception> public DataSet DecompressDataSet(byte[] compressedBytes, SerializationFormat remortingFormat = SerializationFormat.Binary) { var outMs = BytesDeCompress(compressedBytes); #region Deserialize DataSet outDs = new DataSet(); outDs.RemotingFormat = remortingFormat; BinaryFormatter bf = new BinaryFormatter(); outDs = (DataSet)bf.Deserialize(outMs, null); #endregion return outDs; } /// <summary> /// byte[] 압축 해제 한다. /// </summary> /// <param name="compressedBytes">압축 해제할 byte[]</param> /// <returns>압축 해제된 byte[]를 반환 한다.</returns> /// <seealso cref="http://msdn.microsoft.com/ko-kr/library/system.io.compression.deflatestream.aspx"/> /// <remarks> /// byte[]에 대해서 DeflateStream으로 압축 해제 한다. /// 파라메터는 압축된 byte[] 넘겨야 정상 동작 한다. /// </remarks> /// <example> byte[]를 압축 해제 한다. /// <code> /// var compressBytes = BytesCompress(byte[]); /// var outMs = BytesDeCompress(compressBytes); /// </code> /// </example> /// <exception cref="InvalidCastException"> /// </exception> /// <exception cref="ArgumentException"> /// </exception> public Stream BytesDeCompress(byte[] compressedBytes) { #region UnCompress MemoryStream inMs = new MemoryStream(compressedBytes); MemoryStream outMs = null; using (DeflateStream zipStream = new DeflateStream(inMs, CompressionMode.Decompress, true)) { byte[] buffer = new byte[32768]; outMs = new MemoryStream(); //Stream의 모든 데이타를 복사 한다. while (true) { int read = zipStream.Read(buffer, 0, buffer.Length); if (read <= 0) break; outMs.Write(buffer, 0, read); } outMs.Flush(); outMs.Seek(0, 0); //재 사용을 위해 처음으로 되돌린다. zipStream.Flush(); zipStream.Close(); } #endregion return outMs; }
(소스 코드 자체에 주석과 직관적인 코딩으로 충분히 파악이 가능할 것으로 예상하므로 별도의 설명을 생략) |
위 코드에 대해서 사용법과 확인 사항을 테스트 메소드를 통해서 알려 주도록 하겠다.
[TestMethod] public void DataSet_Compress_DeCompress_TestMethod() { //테스트할 DataSet 생성 DataSet ds = new DataSet(); DataTable dt = new DataTable(); ds.Tables.Add(dt); dt.Columns.Add(new DataColumn("column1")); dt.Columns.Add(new DataColumn("column2")); dt.Columns.Add(new DataColumn("column3")); dt.Columns.Add(new DataColumn("column4")); for (int i = 0; i < 100; i++) { var row = dt.NewRow(); row[0] = "value1밸류"; row[1] = "value2밸류"; row[2] = "value3밸류"; row[3] = "value4밸류"; dt.Rows.Add(row); } var compressDs = CompressDataSetBytes(ds); //DataSet을 압축하여 byte[]로 반환 테스트 var temp1 = Convert.ToBase64String(compressDs); //string으로 변환 var temp2 = DecompressDataSet(temp1); //변환된 string이 정상적으로 압축 해제되는지 테스트 var deCompressDs = DecompressDataSet(compressDs); //압축된 byte[]를 압축 해제 테스트 #region 검증 작업 bool isValid = true; foreach (DataRow dr in deCompressDs.Tables[0].Rows) { if ("value1밸류" == dr[0].ToString() && "value2밸류" == dr[1].ToString() && "value3밸류" == dr[2].ToString() && "value4밸류" == dr[3].ToString()) { continue; } else { isValid = false; break; } } #endregion Assert.IsTrue(isValid); //검증 완료 }
실행 시켜 보면 위 코드가 정상적으로 테스트를 통과 하는 것을 볼 수 있을 것이다.
위 부분에서 만든 메소드 중에 DataSet에 대해서만 압축과 해제를 하도록 하지 않는 부분이 있다.
- byte[] BytesCompress(byte[] compressByte)
- Stream BytesDeCompress(byte[] compressedBytes)
이 두 메소드를 이용하면 일반적인 object도 압축과 해제를 할 수 있을것으로 예상하나 아직 테스트를 해보지 안았다. 다음 포스트에 테스트한 것을 올려 보도록 하겠다.
'.Net Framework' 카테고리의 다른 글
[.Net 4.5] 2Gb 이상 메모리 사용 하기 (0) | 2013.02.18 |
---|---|
[Roslyn]The Roslyn Project (0) | 2013.02.18 |
[C# Compress] MemoryStream Compress (0) | 2013.02.15 |
[C# Compress] GZipStream - 문자열 압축과 해제 (0) | 2013.02.15 |
[C# FileSystemWatcher] 디렉토리, 파일 변경 모니터링 클래스 (0) | 2013.02.15 |