LoginSignup
4
3

More than 5 years have passed since last update.

バイナリファイルをシーケンスとして読む

Posted at

バイナリファイルを開いて内容をシーケンスで扱う方法を考えます。

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オブジェクトに対応させてシリアライズ、など出来るようです。
私の用途ではそれほど複雑なフォーマットを必要としていないので上記コードで十分ですが、そのうち試してみるかも。

おわり。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3