VB.NETでもサイズを据え置きでBase64でエンコードしたい

はじめに

突然ですが、Base64ってあるじゃないですか。

Base64 - Wikipedia

任意のバイト列をいわゆるASCII文字集合だけで表現可能で、7ビットしか扱えないメールではUTF-8と組み合わせて使われることが多い奴です。

メールではほぼ必須の技術ですが、どうしてもサイズが元のバイト列よりも大きくなってしまうんですよね。*1

これをどうにかサイズ据え置きでBase64に変換できないかなーと考えた時の記録です。

圧縮ストリーム

まぁ、圧縮ストリームにぶち込んで圧縮して、その結果をBase64のストリームにぶち込んでそのままファイルストリームにぶち込めばサイズ据え置きで7ビット伝送路に通せる形式の完成と洒落込めると思ったのです。

展開する時はその逆ですね。ファイルストリームの結果をBase64デコードストリームに通して解凍ストリームに通せば完成です。

Base64エンコード/デコードストリームはそれっぽい名前のクラスは検索で引っかからなかったのですが、既存のクラスですでに要求を満足するクラスがあるみたいです。

Object-Oriented Software Development: Builtin Base64 Streaming

この方も一回Base64ストリームを自前で実装した後、『ビルトインのクラスでありました』って事っぽいですね。 実を言うと弊社も『なかったら作ればいいじゃない』精神で自前で実装する気満々だったので、危うく同じ轍を踏むところでした。

全体コード

全体のコードはこんな感じですね。 今回はとりあえずファイルに書き出してますけど、書き出し先を別のストリームにすればそのままネットワークに送信できそうですね。

Imports System.IO
Imports System.IO.Compression
Imports System.Security.Cryptography

Module Module1

    Sub Main()
        Dim original = "orig.txt"
        Dim base64 = "base64.txt"
        Dim decoded = "decoded.txt"

        ' 圧縮する方
        Using out = New FileStream(base64, FileMode.OpenOrCreate, FileAccess.Write)
            Using cs = New CryptoStream(out, New ToBase64Transform(), CryptoStreamMode.Write)
                Using ds = New DeflateStream(cs, CompressionMode.Compress)
                    Using fin = New FileStream(original, FileMode.Open, FileAccess.Read)
                        fin.CopyTo(ds)
                    End Using
                End Using
            End Using
        End Using

        ' 解凍する方
        Using out = New FileStream(decoded, FileMode.OpenOrCreate, FileAccess.Write)
            Using fin = New FileStream(base64, FileMode.Open, FileAccess.Read)
                Using cs = New CryptoStream(fin, New FromBase64Transform, CryptoStreamMode.Read)
                    Using ds = New DeflateStream(cs, CompressionMode.Decompress)
                        ds.CopyTo(out)
                    End Using
                End Using
            End Using
        End Using
    End Sub

End Module

どうしてもこのようなStreamをつなげる方法ですと、Usingがネストされてしまいます。

サイズの方はといいますと、このコードが書かれたUTF-8エンコードのテキストファイルですとBase64に変換後のサイズでもオリジナルのサイズ以下になります。 ファイルによって圧縮率も変わるので一概に言えないのですが大体オリジナルのサイズに納まるっぽいですね。

終わりに

なんかこうストリームを繋げて圧縮してBase64に変換して何ちゃらかんちゃらやってますけど、ふと冷静になって見直して思ったのですがコレって何か意味があるのでしょうか。 やってる奴が意味を見出せないのだからまぁ意味が無いと思います。

余談ですが、DeflateStreamのコンストラクタで指定するストリームはCompressionModeによって読み取りか書き出しかが変わります。 CompressionMode.Compressなら書き出し用のストリーム、CompressionMode.Decompressなら読み取り用のストリームを指定しないといけません。 この辺はCryptoStreamみたいに選択ができればいいのにな〜と思いました。

おわり

*1:約4/3程に増加