# Copy File Line by Line Using lazy-seq

**URL:** https://clojureverse.org/t/copy-file-line-by-line-using-lazy-seq/11166
**Category:** Troubleshooting
**Tags:** clojure
**Created:** [January 25, 2025, 4:32pm UTC](https://clojureverse.org/t/copy-file-line-by-line-using-lazy-seq/11166 "2025-01-25T16:32:21Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![patrickbucher](https://clojureverse.org/user_avatar/clojureverse.org/patrickbucher/32/5755_2.png) [@patrickbucher](https://clojureverse.org/u/patrickbucher)
#### Post date: [January 25, 2025, 4:32pm UTC](https://clojureverse.org/t/copy-file-line-by-line-using-lazy-seq/11166/1 "2025-01-25T16:32:21Z")

</div>

I’d like to copy a file line by line using a `lazy-seq` for buffering. The end goal is to filter/transform the lines, so while `slurp`/`spit` certainly would be easier, it doesn’t solve my bigger issue.

Here’s the code:

```clojure
(defn copy-lines [source sink]
  (with-open [r (clojure.java.io/reader source)
              w (clojure.java.io/writer sink)
              lines (line-seq r)]
    (loop [l (first lines)
           ls (rest lines)]
      (when l
        (.write w (str l "\n"))
        (recur (first ls) (rest ls))))))

```

When I run `(copy-lines "foo.txt" "bar.txt")` on a non-empty `foo.txt`, I get the following error message:

```auto
Execution error (IllegalArgumentException) at scratch.core/copy-lines (core.clj:42).
No matching field found: close for class clojure.lang.Cons

```

At some point, the file descriptor must have been replaced by a lazy sequence made up of cons cells; at least that’s what I make out of the error message as a beginner.

Any hints what I’m doing/thinking wrong?

---

<div class="post-metadata">

### Author: ![Harold](https://clojureverse.org/user_avatar/clojureverse.org/harold/32/4796_2.png) [@Harold](https://clojureverse.org/u/Harold)
#### Post date: [January 25, 2025, 4:51pm UTC](https://clojureverse.org/t/copy-file-line-by-line-using-lazy-seq/11166/2 "2025-01-25T16:51:26Z")

</div>

The problem is that you defined `lines` in `with-open`, which calls `.close` on it, and `lines` isn’t the type of thing you can `.close`.

You’ve got the right idea for not holding all of the source file in memory at once. Here’s a working version, in case that’s helpful:

```clojure
user> (spit "foo.txt" "foobar")
nil
user> (slurp "foo.txt")
"foobar"
user> (defn copy-lines [src dest]
        (with-open [r (clojure.java.io/reader src)
                    w (clojure.java.io/writer dest)]
          (->> (line-seq r)
               (run! (fn [l] (.write w (str l "\n")))))))
#'user/copy-lines
user> (copy-lines "foo.txt" "bar.txt")
nil
user> (slurp "bar.txt")
"foobar\n"

```

---

<div class="post-metadata">

### Author: ![patrickbucher](https://clojureverse.org/user_avatar/clojureverse.org/patrickbucher/32/5755_2.png) [@patrickbucher](https://clojureverse.org/u/patrickbucher)
#### Post date: [January 25, 2025, 5:14pm UTC](https://clojureverse.org/t/copy-file-line-by-line-using-lazy-seq/11166/3 "2025-01-25T17:14:58Z")

</div>

Thank you, @Harold, that makes totally sense to me now! The problem wasn’t the actual processing, but abusing `with-open` as a general `let`.

---

<div class="post-metadata">

### Author: ![system](https://clojureverse.org/uploads/default/original/2X/5/51079bf9e4b7d9466242c06cf1e43b9f8bd6da14.png) [@system](https://clojureverse.org/u/system)
#### Post date: [July 27, 2025, 5:15am UTC](https://clojureverse.org/t/copy-file-line-by-line-using-lazy-seq/11166/4 "2025-07-27T05:15:00Z")

</div>

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.
