这段代码在服务器上运行,它检测文件的更改并将其发送到客户端。这是第一次工作,之后文件长度没有得到更新,即使我更改了文件并保存了它。我想clojure不变性就是这里的原因。我怎样才能做到这一点?
(def clients (atom {}))
(def rfiles (atom {}))
(def file-pointers (atom {}))
(defn get-rfile [filename]
(let [rdr ((keyword filename) @rfiles)]
(if rdr
rdr
(let [rfile (RandomAccessFile. filename "rw")]
(swap! rfiles assoc (keyword filename) rfile)
rfile))))
(defn send-changes [changes]
(go (while true
(let [[op filename] (<! changes)
rfile (get-rfile filename)
ignore (println (.. rfile getChannel size))
prev ((keyword filename) @file-pointers)
start (if prev prev 0)
end (.length rfile) // file length is not getting updated even if I changed the file externally
array (byte-array (- end start))]
(do
(println (str "str" start " end" end))
(.seek rfile start)
(.readFully rfile array)
(swap! file-pointers assoc (keyword filename) end)
(doseq [client @clients]
(send! (key client) (json/write-str
{:changes (apply str (map char array))
:fileName filename}))
false))))))
答案 0 :(得分:0)
这里没有不变性。在rfiles
atom中,存储 可变的标准Java对象。
只有当数据追加到文件的末尾时,此代码才能正常工作,并且大小总是在增加。
如果文件中除了最后有更新/添加(长度+ N),指针 start
和end
将不会指向修改后的数据,但只是最后N个字符,您将向客户端发送虚拟内容。
如果删除或任何减少长度的更改,
array (byte-array (- end start))
会抛出你看不到的NegativeArraySizeException
(被go
集团吃掉了吗?)。您可以添加一些(try (...) catch (...))
或测试(- end start)
总是正或空,以管理它并执行相应的行为:重置指针?,...
您是否确定仅扫描更改的文件是否仅通过附加数据进行更改?如果没有,您需要通过相应地重置或更新指针来处理这种情况。
我希望它会有所帮助。
编辑测试环境。
我定义了以下内容。您提供的代码没有变化。
;; define the changes channel
(def notif-chan (chan))
;; define some clients
(def clients (atom {:foo "foo" :bar "bar"}))
;; helper function to post a notif of change in the channel
(defn notify-a-change [op filename]
(go (>! notif-chan [op filename])))
;; mock of the send! function used in send-changes
(defn send! [client message]
(println client message))
;; main loop
(defn -main [& args]
(send-changes notif-chan))
在一个repl中,我跑了:
repl> (-main)
在shell中(我也用编辑器测试过):
sh> echo 'hello there' >> ./foo.txt
在repl中:
repl> (notify-a-change "x" "./foo.txt")
str0 end12
:bar {"changes":"hello there\n","fileName":".\/foo.txt"}
:foo {"changes":"hello there\n","fileName":".\/foo.txt"}
repl> (notify-a-change "x" "./foo.txt")
str12 end12
:bar {"changes":"","fileName":".\/foo.txt"}
:foo {"changes":"","fileName":".\/foo.txt"}
在shell中:
sh> echo 'bye bye' >> ./foo.txt
在repl中:
repl> (notify-a-change "x" "./foo.txt")
str12 end20
:bar {"changes":"bye bye\n","fileName":".\/foo.txt"}
:foo {"changes":"bye bye\n","fileName":".\/foo.txt"}