Как вы записываете файл журнала в Clojure, используя core.async?

Я хочу использовать core.async в качестве регистратора, который записывает данные в файл, поэтому я создал файл test.txt, поместил его в папку ресурсов и написал такой код:

(use 'clojure.java.io)
(use 'clojure.core.async)

(def print-chan (chan))

(go (loop []
      (when-let [v (<! print-chan)]
        (with-open [wrtr (writer "resources/test.txt" :append true)]
          (.write wrtr v))
        (recur)))) 

(>!! print-chan 42)

Однако, когда я запускаю это, я обнаруживаю, что он заменяет только то, что находится в файле, а не добавляет к нему. Кроме того, иногда вывод, который записывается в файл, является нечетным. Однажды я попытался поставить 42 и вместо этого получил *. Когда я использую модуль записи без функций core.async, он работает так, как ожидалось. Каков идиоматический способ записи в файл журнала в Clojure с использованием core.async? Заранее спасибо!

* Я использую световой стол.


person kurofune    schedule 12.05.2014    source источник


Ответы (2)


wrtr – это java.io.BufferedWriter.

Когда вы отправляете 42 (long) в канал, вы вызываете (.write wrtr 42), который вызывает этот метод:

write(int c)
Writes a single character.

42 представляет символ \* в таблице ASCII, так что это то, что записывается.

Вместо этого вы хотите вызвать этот метод Writer через (.write wrtr "42"):

write(String str)
Writes a string.

И вы можете сделать это, преобразовав значения, считанные из канала, в строки:

(.write wrtr (str v))
person danneu    schedule 12.05.2014
comment
Спасибо за этот супер простой и полезный ответ. Единственная проблема, с которой я столкнулся сейчас, это заставить его печатать каждый элемент на новой строке. Должен ли я заглянуть в документацию по Clojure или Java, чтобы понять это? - person kurofune; 13.05.2014
comment
Просто напишите newline после строки журнала. Либо включите его в сообщение: (.write wrtr "42\n"), либо напишите явно: (.write wrtr "\n"). - person liwp; 13.05.2014
comment
Точно. Просто измените строку на (.write wrtr (str v "\n")). - person danneu; 14.05.2014

Вы открываете файл заново в каждом цикле цикла/повторения, поэтому он не добавляется.

Что вам нужно сделать, так это открыть средство записи один раз на всю жизнь программы.

(go
  (with-open [wrtr (writer "resources/test.txt" :append true)]
    (loop []
      (when-let [v (<! print-chan)]
        (.write wrtr (str v "\n"))
      (recur)))) 

Мне просто нужно было написать такой код сегодня. Я обнаружил, что вам нужно вызывать with-open внутри горутины. Из-за этого (я предполагаю) вы не можете использовать макрос with-open с макросом go-loop.

person mattdeboard    schedule 10.09.2015