Clojure 解析一个小的endian二进制文件,填充到一个矩阵中

Clojure 解析一个小的endian二进制文件,填充到一个矩阵中,clojure,Clojure,我有一个包含X×X矩阵的二进制文件。文件本身是一个单精度浮点序列(小尾端)。我想做的是解析它,并将其填充到某种合理的clojure矩阵数据类型中 多亏了,我可以用gloss解析二进制文件。我现在有如下代码: (ns foo.core (:require gloss.core) (:require gloss.io) (:use [clojure.java.io]) (:use [clojure.math.numeric-tower])) (gloss.core/defcodec

我有一个包含X×X矩阵的二进制文件。文件本身是一个单精度浮点序列(小尾端)。我想做的是解析它,并将其填充到某种合理的clojure矩阵数据类型中

多亏了,我可以用gloss解析二进制文件。我现在有如下代码:

(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)
这需要一段时间来运行,但最终会抛出一大串数字。不幸的是,数字全错了。经过进一步调查,这些数字被解读为big endian

假设有某种方法可以将这些二进制文件读取为小endian,我想将结果填充到一个矩阵中。似乎已经决定使用白炽灯与它的平行柯尔特表示,然而,这个问题是从'09年,我希望坚持clojure 1.4和lein 2。在我狂热的谷歌搜索中,我看到了使用jblas或mahout的其他建议。现在有没有一个“最好”的矩阵库

编辑:读取二进制文件非常接近。多亏了这一便利,我能够将内存映射字节缓冲区作为一个简短的单行程序,甚至可以对其重新排序:

(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]>
我希望能够在函数中创建重新排序的字节缓冲区,而无需定义全局变量,但现在似乎不是这样

而且,一旦我对它进行了重新排序,我就不能完全确定如何处理我的DirectByteBuffer,因为它似乎不适合使用。也许对于读取这个缓冲区对象(到JBLAS矩阵中)的剩余步骤,我将创建第二个问题

编辑2:我将下面的答案标记为已接受,因为我认为我原来的问题包含了太多东西。一旦我弄明白了这个问题的其余部分,我将尝试用完整的代码来更新这个问题,这些代码以这个ByteBuffer开头,并读入一个JBLAS矩阵(看起来是正确的数据结构)

如果有人感兴趣,我可以创建一个函数,返回正确排序的bytebuffer,如下所示:

;; 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问题。

打开一个
FileChannel()
,然后获取一个内存映射缓冲区。网上有很多关于这一步骤的教程

通过调用
order(endian ness)
(不是
order的无参数版本)
,将缓冲区的顺序切换到little endian。最后,提取浮点数的最简单方法是对其调用
asFloatBuffer()
,并使用生成的缓冲区读取浮点数

之后,您可以将数据放入所需的任何结构中

下面是一个如何使用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=> 
;;首先,我创建了一个96字节的文件,然后启动了repl
;; 在文件中放入一些小的endian浮动并关闭它
user=>(def文件(java.io.RandomAccessFile.“foo.floats”,“rw”))
#'用户/文件
用户=>(定义通道(.getChannel文件))
#'用户/频道
user=>(def缓冲区(.map channel java.nio.channels.FileChannel$MapMode/READ_WRITE 0 96))
#'用户/缓冲区
user=>(.order buffer java.nio.ByteOrder/LITTLE_ENDIAN)
#
用户=>(def FBUFER(.asFloatBuffer))
#'用户/fbuffer
用户=>(.put fbuffer 0.0)
#
用户=>(.put fbuffer 1 1.0)
#
用户=>(.put fbuffer 2.3)
#
用户=>(.关闭频道)
无
;; 内存映射文件时,尝试读取浮点值,而不更改缓冲区的结尾
user=>(def file2(java.io.RandomAccessFile.foo.floats“r”))
#'用户/文件2
用户=>(def通道2(.getChannel文件2))
#'用户/频道2
user=>(def buffer2(.map channel2 java.nio.channels.FileChannel$MapMode/READ_ONLY 0 96))
#'用户/缓冲区2
用户=>(def fbuffer2(.asFloatBuffer2))
#'用户/fbuffer2
用户=>(.get fbuffer2 0)
0
user=>(.get fbuffer2 1)
4.6006E-41
user=>(.get fbuffer2)
4.1694193E-8
;; 更改缓冲区的顺序并读取浮动
user=>(.order buffer2 java.nio.ByteOrder/LITTLE_ENDIAN)
#
用户=>(def fbuffer2(.asFloatBuffer2))
#'用户/fbuffer2
用户=>(.get fbuffer2 0)
0
user=>(.get fbuffer2 1)
1
user=>(.get fbuffer2)
2.3
用户=>(.关闭通道2)
无
用户=>

您告诉我使用nio对吗?经过一番挖掘,我找到了这个页面(),它看起来像是包装了其中的一些函数。我会做更多的调查看看我能不能弄清楚。你明白了。今天晚些时候,我将尝试添加一个示例。由于“(nio/mmap(nio/channel(io/file)/path/to/file)),我得到了一个DirectByteBuffer。现在来弄清楚顺序。还有,很抱歉有点厚——Java和Clojure还不熟悉。调用此函数并传入Java.nio.ByteOrder/LITTLE_ENDIAN以将其设置为LITTLE ENDIAN。@Peter,这是一个nio错误。请参阅:在版本1.0.2As中,它被修复为以不同的顺序调用它。我不知道。如果不使用clojure nio包装器,您会明白吗?
;; 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=>