我需要在JSON文件中编写一个输出,该文件随着时间的推移会变长。我有什么:
{
"something": {
"foo" : "bar"
}
}
我使用(spit "./my_file" my-text :append true)
。
使用append,我包含新条目,它看起来像这样:
{
"something": {
"foo": "bar"
}
},
{
"something": {
"foo": "bar"
}
},
}
我的问题是我需要这样的东西:
[
{
"something": {
"foo": "bar"
}
},
{
"something": {
"foo": "bar"
}
}
]
但我真的不知道如何在[ ]
答案 0 :(得分:0)
如果您想要就地更新 - 这意味着您更关心性能而不是安全 - 这可以使用java.io.RandomAccessFile来完成:
(import '[java.io RandomAccessFile])
(defn append-to-json-list-in-file [file-name new-json-text]
(let [raf (RandomAccessFile. file-name "rw")
lock (.lock (.getChannel raf)) ;; avoid concurrent invocation across processes
current-length (.length raf)]
(if (= current-length 0)
(do
(.writeBytes raf "[\n") ;; On the first write, prepend a "["
(.writeBytes raf new-json-text) ;; ...before the data...
(.writeBytes raf "\n]\n")) ;; ...and a final "\n]\n"
(do
(.seek raf (- current-length 3)) ;; move to before the last "\n]\n"
(.writeBytes raf ",\n") ;; put a comma where that "\n" used to be
(.writeBytes raf new-json-text) ;; ...then the new data...
(.writeBytes raf "\n]\n"))) ;; ...then a new "\n]\n"
(.close lock)
(.close raf)))
作为使用示例 - 如果不存在预先存在的out.txt
,则接下来三次调用的结果:
(append-to-json-list-in-file "out.txt" "{\"hello\": \"birds\"}")
(append-to-json-list-in-file "out.txt" "{\"hello\": \"trees\"}")
(append-to-json-list-in-file "out.txt" "{\"goodbye\": \"world\"}")
...将是一个包含以下内容的文件:
[
{"hello": "birds"},
{"hello": "trees"},
{"goodbye": "world"}
]
请注意,锁定会阻止多个进程使用相同的输出文件一次调用此代码。 不会在同一进程中为多个线程提供安全性进行并发调用 - 如果您需要,我建议使用代理或其他固有的单线程构造。
如果文件以"\n]\n\n\n"
而不是"\n]\n"
结束,那么还有一些危险可能会破坏已由其他软件编辑的文件,然后在此之前寻找三个字节当前的长度会把我们放在错误的地方,我们会产生错误的输出。
如果您更关心确保输出是完整的而不是损坏的,那么相关技术不是特定于JSON的(并且要求重写整个输出文件,而不是逐步更新它);见Atomic file replacement in Clojure。