Я могу что-то здесь упустить, но что не так со стандартной сериализацией Java? Слишком медленный, слишком большой, что-то еще?
Оболочка Clojure для простой сериализации Java может выглядеть примерно так:
(defn serializable? [v]
(instance? java.io.Serializable v))
(defn serialize
"Serializes value, returns a byte array"
[v]
(let [buff (java.io.ByteArrayOutputStream. 1024)]
(with-open [dos (java.io.ObjectOutputStream. buff)]
(.writeObject dos v))
(.toByteArray buff)))
(defn deserialize
"Accepts a byte array, returns deserialized value"
[bytes]
(with-open [dis (java.io.ObjectInputStream.
(java.io.ByteArrayInputStream. bytes))]
(.readObject dis)))
user> (= (range 10) (deserialize (serialize (range 10))))
true
Есть значения, которые нельзя сериализовать, например, Потоки Java и атом Clojure / агент / будущее, но он должен работать для большинства простых значений, включая примитивы и массивы Java, а также функции, коллекции и записи Clojure.
Сохраните ли вы что-нибудь на самом деле, зависит. В моем ограниченном тестировании небольших наборов данных сериализация в текстовый и двоичный формат выглядит примерно одинаково по времени и пространству.
Но для особого случая, когда большая часть данных представляет собой массивы примитивов Java, сериализация Java может быть на несколько порядков быстрее и сэкономить значительную часть пространства. (Быстрый тест на ноутбуке, 100 Кб случайных байтов: сериализация 0,9 мс, 100 КБ; текст 490 мс, 700 КБ.)
Обратите внимание, что тест (= new-data orig-data)
не работает для массивов (он делегирует Java 1015 *, который для массивов просто проверяет, является ли это один и тот же объект), поэтому вам может потребоваться / нужно написать собственную функцию равенства для проверить сериализацию.
user> (def a (range 10))
user> (= a (range 10))
true
user> (= (into-array a) (into-array a))
false
user> (.equals (into-array a) (into-array a))
false
user> (java.util.Arrays/equals (into-array a) (into-array a))
true