Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing to a file in Clojure

Tags:

java

clojure

I am using this function to write to a file in Clojure.


(defn writelines [file-path lines]
  (with-open [wtr (clojure.java.io/writer file-path)]
    (doseq [line lines] (.write wtr line))))

But this always generates this error:

IllegalArgumentException No matching method found: write for 
class java.io.BufferedWriter in
clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:79)

What am I doing wrong here?

like image 495
abc def foo bar Avatar asked Dec 19 '11 07:12

abc def foo bar


2 Answers

First of all, your function works just fine for many inputs:

Clojure 1.3.0
user=> (defn writelines [file-path lines]
  (with-open [wtr (clojure.java.io/writer file-path)]
    (doseq [line lines] (.write wtr line))))
#'user/writelines
user=> (writelines "foobar" ["a" "b"])
nil
user=> (writelines "quux" [1 2])
nil

However, when you try to pass in something weird we get the error you describe:

user=> (writelines "quux" [#{1}])
IllegalArgumentException No matching method found: write for class  java.io.BufferedWriter  clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:79)

This error is because BufferedWriter has multiple overloaded versions of write and clojure doesn't know which one to call. In this case the conflicting ones are write(char[]) and write(String). With inputs like strings ("a") and integers (1) clojure knew to call the String version of the method, but with something else (e.g. a clojure set, #{1}) clojure couldn't decide.

How about either ensuring that the inputs to writelines are indeed Strings or stringifying them using the str function?

Also, have a look at the spit function.

like image 72
opqdonut Avatar answered Oct 03 '22 06:10

opqdonut


Try this:

(defn writelines [file-path lines]
  (with-open [wtr (clojure.java.io/writer file-path)]
    (binding [*out* wtr]
      (doseq [line lines] (print wtr line)))))

If you look at the documentation for BufferedWriter you'll see no corresponding method to the way you were calling write (whoops, I missed the inherited methods, silly me!). Binding to *out* is just easier all around, I think (unless you also want to be outputting debugging information, in which case it might be a bit trickier).

like image 33
mange Avatar answered Oct 03 '22 05:10

mange