バイナリファイルを開いて内容をシーケンスで扱う方法を考えます。
Java標準ライブラリを使う
(defn read-as-byte-buffer [filename]
(with-open [fis (java.io.FileInputStream. filename)]
(let [channel (.getChannel fis)
byte-buf (java.nio.ByteBuffer/allocate (.size channel))]
(.read channel byte-buf)
byte-buf)))
返り値はjava.nio.ByteBufferで返ってきます。あとは次のようにしてやればシーケンスとして扱える。
シーケンスに変換
(defn byte-buf->seq [byte-buf]
(for [idx (range (.limit byte-buf))]
(.get byte-buf idx)))
確認
なにか適当なファイルをこの方法で読んでみます。
; echo "hello clojure" |gzip -c > hello.txt.gz
(def bb (read-as-byte-buffer "hello.txt.gz"))
(def bs (byte-buf->seq bb))
(take 10 bs)
;=> (31 -117 8 0 74 81 -59 85 0 3)
(map #(format "%02x " %) (take 16 bs))
;=> ("1f " "8b " "08 " "00 " "4a " "51 " "c5 " "55 " "00 " "03 " "cb " "48 " "cd " "c9 " "c9 " "57 ")
$ od -t x1 hello.txt.gz
0000000 1f 8b 08 00 4a 51 c5 55 00 03 cb 48 cd c9 c9 57
...
どうやらちゃんと読めているみたいですね。
注意
Javaのbyte型は8ビットの 符号付き 整数です。0〜255だと思ってるとハマるので注意。
Java触りたくない!
clojurewerkz/buffy というライブラリがあります。 Buffy The ByteBuffer Slayer という力強いスローガンが掲げられているので触ってみると良いんじゃないでしょうか。
READMEをざっと読むとバイナリフォーマットを定義してClojureオブジェクトに対応させてシリアライズ、など出来るようです。
私の用途ではそれほど複雑なフォーマットを必要としていないので上記コードで十分ですが、そのうち試してみるかも。
おわり。