![見出し画像](https://assets.st-note.com/production/uploads/images/124593372/rectangle_large_type_2_7f14355f965cc84bfa2df86235d6d82c.png?width=1200)
Unityでzstd圧縮と解凍
Unityでfacebookのzstdを利用して圧縮と解凍を行う。
CompressLevelは1(低圧縮)~22(高圧縮)を選択可能
今回はC#でzstdを使うために
https://github.com/bp74/Zstandard.Net
を利用した。
Unityで使用するためにZstandard.Netをクローンし、VisualStudioでビルド
Zstandard.Net.dll
libzstd.dll
をUnityプロジェクトのPluginフォルダにインポート
![](https://assets.st-note.com/img/1702602664209-oqXwWttJMp.png)
以下がUnityでzstdを用いた圧縮、解凍のサンプルコード
Spaceキーを押すとテストデータの圧縮、解凍のテストを行い、結果をDebug.Logで出力します。
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using UnityEngine;
using Zstandard.Net;
public class ZstdTest : MonoBehaviour
{
[Range(1, 22)] public int compressLevel = 11;
public int testDataSizeKb = 10;
private byte[] _compressed;
private byte[] _output;
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
CompressTest();
}
}
private void CompressTest()
{
var compressStartTime = DateTime.Now;
var bytes = CreateRandomBytesWithText(testDataSizeKb * 1024);
var log = $"Original: {ConvertUnit(bytes.Length)}\n";
//Compress
using (var memoryStream = new MemoryStream())
using (var compressionStream = new ZstandardStream(memoryStream, CompressionMode.Compress))
{
compressionStream.CompressionLevel = compressLevel;
compressionStream.Write(bytes, 0, bytes.Length);
compressionStream.Close();
_compressed = memoryStream.ToArray();
log += $"Compressed: {ConvertUnit(bytes.Length)} -> {ConvertUnit(_compressed.Length)}\n";
log += $"Checksum: {GetChecksum(bytes)} -> {GetChecksum(_compressed)}\n";
}
//Decompress
using (var memoryStream = new MemoryStream(_compressed))
using (var compressionStream = new ZstandardStream(memoryStream, CompressionMode.Decompress))
using (var temp = new MemoryStream())
{
compressionStream.CopyTo(temp);
_output = temp.ToArray();
log += $"Decompressed: {ConvertUnit(_compressed.Length)} -> {ConvertUnit(_output.Length)}\n";
log += $"Checksum: {GetChecksum(_compressed)} -> {GetChecksum(_output)}\n";
}
var compressEndTime = DateTime.Now;
log += $"CompressTime: {(compressEndTime - compressStartTime).TotalMilliseconds}ms\n";
Debug.Log(log);
}
private static byte[] CreateRandomBytesWithText(int size)
{
var bytes = new byte[size];
var rand = new System.Random();
const string text = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (var i = 0; i < size; i++)
{
if (rand.Next(0, 100) < 50)
{
bytes[i] = (byte)text[rand.Next(0, text.Length)];
}
else
{
bytes[i] = (byte)rand.Next(0, 256);
}
}
return bytes;
}
private static ushort GetChecksum(IReadOnlyList<byte> bytes)
{
ushort checksum = 0;
foreach (var t in bytes)
{
checksum += t;
}
return checksum;
}
private static string ConvertUnit(long size)
{
var unit = new[] { "B", "KB", "MB", "GB", "TB" };
var index = 0;
var fsize = (float)size;
while (fsize > 1024f)
{
fsize /= 1024f;
index++;
}
return $"{fsize:F2}{unit[index]}";
}
}
入力データにもよるが、サンプルコード内のCreateRandomBytesWithTextメソッドを使って生成したランダムデータでの圧縮時間と、圧縮サイズを計測した結果が以下。
結論CompressLevelは扱うデータによって良いレベルを選択したい。
![](https://assets.st-note.com/img/1702600960933-yn5kKaDO7X.png)
![](https://assets.st-note.com/img/1702600984473-eXm7W5DOnS.png)
![](https://assets.st-note.com/img/1702600998985-m90nFu2QwN.png)