我有一个包含 X × X 矩阵的二进制文件。文件本身是一个单精度浮点数(小端)序列。我想做的就是解析它,并将其填充到一些合理的 clojure 矩阵数据类型中。
谢谢这个问题 https://stackoverflow.com/questions/749871/how-to-parse-binary-files-in-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)
这需要一段时间才能运行,但最终会转储出一大串数字。不幸的是,这些数字都是错误的。经过进一步调查,这些数字被读取为大端字节序。
假设有某种方法可以将这些二进制文件作为小端读取,我想将结果填充到一个矩阵中。这个问题 https://stackoverflow.com/questions/1674335/clojure-matrix-representation似乎已经决定使用 Incanter 及其 Parallel Colt 表示形式,但是,这个问题来自 09 年,我希望坚持使用 clojure 1.4 和 lein 2。在我疯狂的谷歌搜索中,我看到了其他使用 jblas 的建议或象夫。如今有 clojure 的“最佳”矩阵库吗?
EDIT:读取二进制文件非常接近。多亏了这个方便蔚来包装器 https://github.com/pjstadig/nio,我能够获得一个内存映射字节缓冲区作为短单行,甚至可以重新排序:
(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 矩阵)的剩余步骤,我将创建第二个问题。
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 问题。