如何使用core.async在Clojure中写入日志文件?

3

我想使用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函数,那么它就能按预期工作。使用core.async在Clojure中写入日志文件的惯用方法是什么?谢谢!*我正在使用Light Table。
2个回答

4

wrtr 是一个 java.io.BufferedWriter

当你将 42 (long) 发送到通道中时,你正在调用 (.write wrtr 42) 方法,该方法会调用以下方法:

write(int c)
Writes a single character.

42代表ASCII表上的\*字符,因此这就是所写的内容。

相反,您希望通过(.write wrtr "42")调用此Writer方法:

write(String str)
Writes a string.

您可以通过将从通道读取的值转换为字符串来实现:

(.write wrtr (str v))

谢谢你提供这个超级简单和有用的答案。我现在唯一的问题是如何让它将每个项目打印到新行。我应该查看Clojure或Java文档来解决这个问题吗? - kurofune
1
在你的日志行后面,只需写一个 newline。可以将其包含在消息中:(.write wrtr "42\n"),也可以明确地写出来:(.write wrtr "\n") - liwp
没错。只需将该行更改为 (.write wrtr (str v "\n")) - danneu

3
你在每个循环/递归周期中都重新打开了文件,这就是为什么它没有追加的原因。
你需要做的是为程序的整个生命周期只打开一次writer。
(go
  (with-open [wrtr (writer "resources/test.txt" :append true)]
    (loop []
      (when-let [v (<! print-chan)]
        (.write wrtr (str v "\n"))
      (recur)))) 

今天我刚写了这样的代码。我发现你必须在 goroutine 中调用 with-open。因为这个原因(我猜),你不能在 go-loop 宏中使用 with-open 宏。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接