【C#】Zip圧縮できないファイルを作成するツール

タイトルの通りZip圧縮しても圧縮率0パーセントで圧縮前と後でサイズがほぼ変わらないファイルを作成するツールを作ってみました。

作成環境

  • .NET Frmamework 4.7.2(C#7.3)
  • VisualStudio 2019
  • Windows Form

成果物

コードとソリューション・バイナリは Github にあります。

github.com

ツールの見た目はこんな感じです。

f:id:Takachan:20210604220216p:plain

サイズを入力してCreateを押せば指定したフォルダにファイルが作成されます。

ツールの見た目

Windows Form でライブラリをラップしています。

  • FileCreateForm.cs、画面のコード
  • DummyFileUtil、ファイルを作るためのクラス

Zip圧縮しても圧縮されない性質は、ファイル内の全隣接バイトがバイト単位で異なっていれば圧縮されないので、乱数を使って以下のように記述して任意の文字数を書き込むと実現できます。

FileStream fs = new FileStream(filePath, FileMode.Create);

for(int i = 0; i < len; i++)
    fs.WriteByte((byte)r.Next(min, max)); // randはRandomクラスのインスタンス

肝心の処理は DummyFileUtil に書いてあります。

// 1つファイルを作成する
public static async Task CreateFile(string filePath, uint fileSize, 
    byte complexity = byte.MaxValue,  IProgress<double> progress = null,
        CancellationToken ct = default)

// 複数件ファイルを作成する
public static async Task CreateFiles(string dir, string fileName, uint fileCount, 
    uint fileSize, byte complexity = byte.MaxValue, 
        IProgress<double> progress = null, CancellationToken ct = default)

complexity がバイトごとに使用する文字数を表します。1で1文字しか使わない = ファイル内はすべて同じ文字なる = zip圧縮率が最大となります。大きくすると使用する文字が多くなって圧縮率が下がります。255を指定すればzipではほぼ圧縮できないファイルが作成できます。

async なので進捗通知は IProgress経由、キャンセルは CancellationToken の ThrowIfCancellationRequested で実装しています。

private static async Task createFileCore(string filePath, uint fileSize, 
    byte min, byte max, IProgress<double> progress, CancellationToken ct)
{
    await Task.Run(() =>
    {
        try
        {
            var r = new Random(); // 高速で並列実行起動を想定しない
            using (var fs = new FileStream(filePath, FileMode.Create))
            {
                for (long i = 0; i < fileSize; i++)
                {
                    ct.ThrowIfCancellationRequested();

                    if (i % 1024 == 0)
                    {
                        // 間違ってテキストで開くと大変なことになるので適当に改行
                        fs.WriteByte((byte)'\n');
                    }
                    else
                    {
                        fs.WriteByte((byte)r.Next(min, max));
                    }

                    if (progress != null && i % 1024 == 0)
                    {
                        double value = (i + 1) / (double)fileSize;
                        progress.Report(value);
                    }
                }
            }
        }
        catch (OperationCanceledException ex)
        {
            System.Diagnostics.Debug.WriteLine($"{ex}, path='{filePath}'");
            if (File.Exists(filePath)) File.Delete(filePath);
        }
    });
}

Github Releaseににバイナリをアップ時の注意

VisualStudio の Release ビルドでビルドしたものを配布する時は一緒に生成された PDB を削除するのではなく、プロパティ > 出力 > デバッグ情報 を「なし」にしてからビルドしないと exe の中に自分の PC のパスが入ってしまうので思わぬ身バレとかがあるかもしれないので設定を忘れないようにしましょう。当然 PDB は配布パッケージの中には含めないようにしましょう。

簡単ですが以上です。