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;
}



 

(소스 코드 자체에 주석과 직관적인 코딩으로 충분히 파악이 가능할 것으로 예상하므로 별도의 설명을 생략)
※ 장황한 설명 보다는 주석과 소스코드 자체 만으로도 이해할 수 있도록 포스팅을 하는데 주안점을 두도록 하였습니다. 실제 개발에서 필요한 소스는 단순히 Copy & Paste 만으로도 사용할 수 있도록 노력할 것이며 주석을 이용해 nDoc이나 별도의 자동 DOC 제작 유틸로 API 문서를 만드는 데에도 도움이 되었으면 한다.
DOC에 대한 프로그램 정보 정보 Util link


위 코드에 대해서 사용법과 확인 사항을 테스트 메소드를 통해서 알려 주도록 하겠다.

[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도 압축과 해제를 할 수 있을것으로 예상하나 아직 테스트를 해보지 안았다. 다음 포스트에 테스트한 것을 올려 보도록 하겠다.


Posted by 퓨전마법사
,