0

这段代码在服务器上运行,它检测文件的更改并将其发送给客户端。这是第一次工作,之后文件长度没有得到更新,即使我更改了文件并保存了它。我想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))))))
4

1 回答 1

0

这里没有不变性。在atom 中,存储可变的rfiles标准 Java 对象。

仅当数据附加到文件末尾并且大小始终在增加时,此代码才能正常工作。

如果文件中有更新/添加(长度+N)而不是结尾,则指针不会 指向修改后的数据,而只会指向最后N个字符,您将向客户端发送虚拟内容.startend

如果有删除或任何减少长度的更改,

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)

在外壳中(我也用编辑器测试过):

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"}

在外壳中:

sh> echo 'bye bye' >> ./foo.txt

在一个回复中:

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"}
于 2015-03-05T12:21:17.273 回答