【问题标题】:How to read a whole binary file (Nippy) into byte array in Clojure?如何在 Clojure 中将整个二进制文件(Nippy)读入字节数组?
【发布时间】:2014-05-25 23:30:45
【问题描述】:

我需要将存储在磁盘上的 Nippy 数据结构转换成 Nippy 可以读取的东西吗? Nippy 使用字节数组,所以我需要一些方法将文件转换为字节数组。我试过了

(clojure.java.io/to-byte-array (clojure.java.io/file folder-path file-path))

但这给了

java.lang.IllegalArgumentException: Value out of range for byte: ? 

那我试试:

(into-array Byte/TYPE  (map byte (slurp (clojure.java.io/file folder-path file-path)))) 

但是不知何故命名空间是错误的,我找不到正确的。

首先要编写 Nippy 结构,我使用的是:

(with-open [w (clojure.java.io/output-stream file-path)]
    (.write w (nippy/freeze data)))))

【问题讨论】:

    标签: file serialization clojure binary bytearray


    【解决方案1】:

    这是我使用 clojure 内置插件的一般做法

    (defn slurp-bytes
      "Slurp the bytes from a slurpable thing"
      [x]
      (with-open [out (java.io.ByteArrayOutputStream.)]
        (clojure.java.io/copy (clojure.java.io/input-stream x) out)
        (.toByteArray out)))
    

    【讨论】:

    • 非常感谢您写下这个答案,它在我将图像转换为 base64 UTF8 字符串的过程中帮助了我很多。
    • 这很好,但输入流应该在 with-open 绑定中。您可以将输入和输出绑定在同一个with-open
    【解决方案2】:

    我不知道 Clojure 内置的任何东西可以处理这个问题。你肯定不想要slurp,因为这会将流内容解码为文本。

    您可以编写自己的方法来执行此操作,基本上是从InputStream 读取到缓冲区并将缓冲区写入java.io.ByteArrayOutputStream。或者您可以使用来自 Apache Commons IO 的 IOUtils class

     (require '[clojure.java.io :as io])
     (import '[org.apache.commons.io IOUtils])
    
     (IOUtils/toByteArray (io/input-stream file-path))
    

    您还应该看看 Nippy 的 thaw-from-in!freeze-to-out! 函数:

     (import '[java.io DataInputStream DataOutputStream])
    
     (with-open [w (io/output-stream file-path)]
       (nippy/freeze-to-out! (DataOutputStream. w) some-data))
    
     (with-open [r (io/input-stream file-path)]
       (nippy/thaw-from-in! (DataInputStream. r)))
    

    【讨论】:

      【解决方案3】:

      既然知道文件的.length,就可以分配一次,使用DataInputStreamreadFully方法。不需要额外的库、缓冲区副本或循环。

      (defn file-to-byte-array
        [^java.io.File file]
        (let [result (byte-array (.length file))]
          (with-open [in (java.io.DataInputStream. (clojure.java.io/input-stream file))]
            (.readFully in result))
          result))
      

      【讨论】:

        【解决方案4】:

        一个快速的临时解决方案可能是这个代码:

        (defn slurpb [is]
          "Convert an input stream is to byte array"
          (with-open [baos (java.io.ByteArrayOutputStream.)]
            (let [ba (byte-array 2000)]
              (loop [n (.read is ba 0 2000)]
                (when (> n 0)
                  (.write baos ba 0 n)
                  (recur (.read is ba 0 2000))))
              (.toByteArray baos))))
        
        ;;test
        (String. (slurpb (java.io.ByteArrayInputStream. (.getBytes "hello"))))
        

        【讨论】:

          【解决方案5】:

          请注意,我刚刚删除了 Nippy v2.13.0,它现在包括一对帮助简化此用例的辅助工具:freeze-to-filethaw-from-file

          发布详情:https://github.com/ptaoussanis/nippy/releases/tag/v2.13.0

          干杯!

          【讨论】:

            【解决方案6】:

            你可以试试 ClojureWerk 的 Buffy:https://github.com/clojurewerkz/buffy

            Buffy 是一个 Clojure 库,用于处理二进制数据、在 Clojure 中编写完整的二进制协议实现、在堆外缓存中存储复杂的数据结构、读取二进制文件以及执行您通常使用 ByteBuffer 执行的所有操作。

            如果你的二进制数据是结构化的,那就太好了,因为你可以根据结构类型定义复杂的复合类型和帧,甚至解码 UTF。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-10-29
              • 1970-01-01
              • 1970-01-01
              • 2011-05-14
              • 1970-01-01
              相关资源
              最近更新 更多