问题
I want to use core.async as a logger that writes out to a file, so I created a test.txt file, stuck it in my resources folder and wrote this code:
(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)
When I run this, however, I find that it will only replace what is in the file, and not append to it. Also, sometimes the output that is written to the file is odd. Once, I tried to put 42 and I got * instead. When I use the writer without the core.async functions, it works as expected. What is the idiomatic way to write to a log file in Clojure using core.async? Thanks in advance!
*I am using light table.
回答1:
wrtr
is a java.io.BufferedWriter.
When you send 42
(long) into the channel, you're calling (.write wrtr 42)
which invokes this method:
write(int c)
Writes a single character.
42
represents the \*
character on the ASCII table so that's what's being written.
Instead, you want to invoke this Writer method via (.write wrtr "42")
:
write(String str)
Writes a string.
And you can do that by converting the values read from the channel into strings:
(.write wrtr (str v))
回答2:
You are opening the file anew in each loop/recur cycle, this is why it's not appending.
What you need to do is open the writer once for the life of the program.
(go
(with-open [wrtr (writer "resources/test.txt" :append true)]
(loop []
(when-let [v (<! print-chan)]
(.write wrtr (str v "\n"))
(recur))))
I just had to write code like this today. What I found was that you have to call with-open
inside the goroutine. Because of this (I assume), you can't use the with-open
macro with the go-loop
macro.
来源:https://stackoverflow.com/questions/23600387/how-do-you-write-to-a-log-file-in-clojure-using-core-async