0

Этот фрагмент кода запускается на сервере и обнаруживает изменения в файле и отправляет его клиенту. Это работает впервые, и после этого длина файла не обновляется, даже я изменил файл и сохранил его. Я предполагаю, что неизменность clojure является причиной здесь. Как я могу сделать эту работу?Получение того же экземпляра RandomAccessFile в 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

Здесь нет неизменности. В атоме rfiles вы храните стандартные объекты Java, которые являются mutable.

Этот код работает хорошо, только если данные добавлены в конец файла, и размер всегда увеличивается.

Если есть обновление/дополнение (длины + N) в другой файл, чем в конце концов, указателиstart и end не будет указывать на измененные данные, но только последние N символов и вы отправите фиктивные вещи клиентам.

Если есть удаление или какие-либо изменения, которые уменьшают длину,

array (byte-array (- end start)) 

будет бросать NegativeArraySizeException вы не видите (съеден go блока?). Вы можете добавить (try (...) catch (...)) или проверить, что (- end start) всегда положительный или нулевой, чтобы управлять им и выполнять соответствующее поведение: сброс указателей? ...

Вы уверены, что файлы, которые вы просматриваете для изменений, изменяются только с помощью добавления данные? Если нет, вам необходимо обработать этот случай, соответственно сбросив или обновив указатели.

Надеюсь, это поможет.


EDIT тестовой среды.

Я определил следующее. Нет никакого изменения кода, который вы предоставили.

;; 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> (-main) 

в оболочке (я тестировал с редактором тоже):

sh> echo 'hello there' >> ./foo.txt 

в РЕПЛ:

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

Спасибо за ответ. Я уверен, что добавляю данные в конец файла. Этот код отправляет добавленные изменения клиенту, если я каждый раз создаю новый RandomAccessFile, а не кеширую файловый объект. (println (str «str» start «end» end)) сообщает мне, что после создания файла его размер остается неизменным. Поэтому я думал, что get-rfile всегда дает новую копию. – FourOfAKind

+0

Я тестировал код локально, и когда я добавляю некоторые данные в файл (например, «echo» hello »>>./Foo.txt' или с помощью редактора), а затем отправляю изменения на канал« changes », изменение обнаружено и зарегистрирует правильную информацию. И когда я повторяю процесс, он работает нормально. Я не думаю, что проблема возникает из 'get-rfile' или' file-pointers' **, если ** никакой другой процесс не возится с файлом данных ... –

+0

Thats interesting. Для этого я использую TextEdit. Я попробую использовать другой редактор и увижу, не имеет значения. (Я не думаю, что это будет). – FourOfAKind