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