VB.NETでもサイズを据え置きでBase64でエンコードしたい
はじめに
突然ですが、Base64ってあるじゃないですか。
任意のバイト列をいわゆる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程に増加