3

X x X 行列を含むバイナリ ファイルがあります。ファイル自体は、単精度浮動小数点 (リトルエンディアン) のシーケンスです。私がやりたいのは、それを解析して、適切な clojure マトリックス データ型に詰め込むことです。

この質問のおかげで、グロスでバイナリファイルを解析できることがわかりました。私は今、次のようなコードを持っています:

(ns foo.core
  (:require gloss.core)
  (:require gloss.io)
  (:use [clojure.java.io])
  (:use [clojure.math.numeric-tower]))

(gloss.core/defcodec mycodec
  (gloss.core/repeated :float32 :prefix :none))

(def buffer (byte-array (* 1200 1200)))

(.read (input-stream "/path/to/binaryfile") buffer)

(gloss.io/decode mycodec buffer)

これには実行に時間がかかりますが、最終的には膨大な数のリストが出力されます。残念ながら、数字はすべて間違っています。さらに調査したところ、数字はビッグエンディアンとして読み取られました。

これらのバイナリ ファイルをリトルエンディアンとして読み取る何らかの方法があると仮定して、結果を行列に詰め込みたいと思います。この質問は、Parallel Colt 表現で Incanter を使用することに落ち着いたようですが、その質問は '09 年のものであり、私は clojure 1.4 と lein 2 に固執することを望んでいます。 jblas または mahout を使用します。最近、clojure に「最適な」マトリックス ライブラリはありますか?

編集: バイナリ ファイルの読み取りは非常に近いです。この便利なnio wrapperのおかげで、メモリ マップされたバイト バッファーを短いワンライナーとして取得し、並べ替えることもできます。

(ns foo.core
  (:require [clojure.java.io :as io])
  (:require [nio.core :as nio])
  (:import [java.nio ByteOrder]))

(def buffer (nio/mmap "/path/to/binaryfile"))

(class buffer) ;; java.nio.DirectByteBuffer

(.order buffer java.nio.ByteOrder/LITTLE_ENDIAN)
;; #<DirectByteBuffer java.nio.DirectByteBuffer[pos=0 lim=5760000 cap=5760000]>

ただし、中間 (def) ステップを実行せずに並べ替えを行うと、次のように失敗します。

(.order (nio/mmap f) java.nio.ByteOrder/LITTLE_ENDIAN)

;; clojure.lang.Compiler$CompilerException: java.lang.IllegalArgumentException: Unable to resolve classname: MappedByteBuffer, compiling:(/Users/peter/Developer/foo/src/foo/core.clj:12)
;;  at clojure.lang.Compiler.analyzeSeq (Compiler.java:6462)
;;     clojure.lang.Compiler.analyze (Compiler.java:6262)
;; etc...

グローバル変数を定義せずに関数内で並べ替えられたバイトバッファを作成できるようにしたいのですが、今のところそれは好きではないようです。

また、順序を変更した後は、反復可能ではないように見えるため、DirectByteBuffer をどうするか完全にはわかりません。おそらく、このバッファ オブジェクトを (JBLAS マトリックスに) 読み込む残りの手順として、2 つ目の質問を作成します。

EDIT 2:元の質問があまりにも多くのものを組み合わせていると思うので、以下の回答を承認済みとしてマークしています。この残りの部分を理解したら、この ByteBuffer で始まり、JBLAS マトリックス (正しいデータ構造のように見える) に読み込まれる完全なコードでこの質問を更新しようとします。

誰かが興味を持っている場合に備えて、次のように適切に順序付けられたバイトバッファを返す関数を作成できました。

;; This works!
(defn readf [^String file]
  (.order
   (.map
    (.getChannel
     (java.io.RandomAccessFile. file "r"))
    java.nio.channels.FileChannel$MapMode/READ_ONLY 0 (* 1200 1200))
   java.nio.ByteOrder/LITTLE_ENDIAN))

私が見つけたnioラッパーは、これをかなり単純化/きれいにしているように見えますが、正しく使用していないか、何か問題があるように見えます. nio ラッパーを使用して調査結果を要約するには、次のようにします。

;; this works
(def buffer (nio/mmap "/bin/file"))
(def buffer (.order buffer java.nio.ByteOrder/LITTLE_ENDIAN))
(def buffer (.asFloatBuffer buffer))

;; this fails
(def buffer
  (.asFloatBuffer
   (.order
    (nio/mmap "/bin/file")
    java.nio.ByteOrder/LITTLE_ENDIAN)))

悲しいことに、これは別の日の clojure の謎、またはおそらく別の StackOverflow の質問です。

4

1 に答える 1

2

を開き、FileChannel()メモリ マップド バッファを取得します。この手順については、ウェブ上に多くのチュートリアルがあります。

order(endian-ness)(引数のないバージョンの ではなく)を呼び出して、バッファーの順序をリトル エンディアンに切り替えますorder。最後に、float を抽出する最も簡単な方法はasFloatBuffer()、それを呼び出し、結果のバッファーを使用して float を読み取ることです。

その後、必要な構造にデータを配置できます。

編集API の使用方法の例を次に示します。

;; first, I created a 96 byte file, then I started the repl
;; put some little endian floats in the file and close it
user=> (def file (java.io.RandomAccessFile. "foo.floats", "rw"))
#'user/file
user=> (def channel (.getChannel file))
#'user/channel
user=> (def buffer (.map channel java.nio.channels.FileChannel$MapMode/READ_WRITE 0 96))
#'user/buffer
user=> (.order buffer java.nio.ByteOrder/LITTLE_ENDIAN)
#<DirectByteBuffer java.nio.DirectByteBuffer[pos=0 lim=96 cap=96]>
user=> (def fbuffer (.asFloatBuffer buffer))
#'user/fbuffer
user=> (.put fbuffer 0 0.0)
#<DirectFloatBufferU java.nio.DirectFloatBufferU[pos=0 lim=24 cap=24]>
user=> (.put fbuffer 1 1.0)
#<DirectFloatBufferU java.nio.DirectFloatBufferU[pos=0 lim=24 cap=24]>
user=> (.put fbuffer 2 2.3)
#<DirectFloatBufferU java.nio.DirectFloatBufferU[pos=0 lim=24 cap=24]>
user=> (.close channel)
nil

;; memory map the file, try reading the floats w/o changing the endianness of the buffer
user=> (def file2 (java.io.RandomAccessFile. "foo.floats" "r"))
#'user/file2
user=> (def channel2 (.getChannel file2))                                                
#'user/channel2
user=> (def buffer2 (.map channel2 java.nio.channels.FileChannel$MapMode/READ_ONLY 0 96))
#'user/buffer2
user=> (def fbuffer2 (.asFloatBuffer buffer2))
#'user/fbuffer2
user=> (.get fbuffer2 0)
0.0
user=> (.get fbuffer2 1)
4.6006E-41
user=> (.get fbuffer2 2)
4.1694193E-8

;; change the order of the buffer and read the floats    
user=> (.order buffer2 java.nio.ByteOrder/LITTLE_ENDIAN)                                 
#<DirectByteBufferR java.nio.DirectByteBufferR[pos=0 lim=96 cap=96]>
user=> (def fbuffer2 (.asFloatBuffer buffer2))
#'user/fbuffer2
user=> (.get fbuffer2 0)
0.0
user=> (.get fbuffer2 1)
1.0
user=> (.get fbuffer2 2)
2.3
user=> (.close channel2)
nil
user=> 
于 2012-10-26T04:12:19.023 に答える