Skip to content

Instantly share code, notes, and snippets.

@edw
Last active November 12, 2021 20:31
Show Gist options
  • Save edw/5128978 to your computer and use it in GitHub Desktop.
Save edw/5128978 to your computer and use it in GitHub Desktop.
To delete a directory recursively in Clojure.
(defn delete-recursively [fname]
(let [func (fn [func f]
(when (.isDirectory f)
(doseq [f2 (.listFiles f)]
(func func f2)))
(clojure.java.io/delete-file f))]
(func func (clojure.java.io/file fname))))
@LouisBurke
Copy link

Brilliant.

@erdos
Copy link

erdos commented Jan 3, 2017

this does the same using the build-in file-seq function to enumerate the contents of the directory.

(defn delete-recursively [fname]
  (doseq [f (reverse (file-seq (clojure.java.io/file fname)))]
     (clojure.java.io/delete-file f)))

@ulsa
Copy link

ulsa commented May 18, 2017

It's elegant, but I'm not sure it's as robust for large trees as the recursive version. reverse removes the laziness of file-seq.

@ignorabilis
Copy link

Using letfn will simplify things a bit (no need for (func func )). Also you can expose the silently argument:

(defn delete-files-recursively [fname & [silently]]
  (letfn [(delete-f [file]
            (when (.isDirectory file)
              (doseq [child-file (.listFiles file)]
                (delete-f child-file)))
            (clojure.java.io/delete-file file silently))]
    (delete-f (clojure.java.io/file fname))))

@leontalbot
Copy link

Nice, thanks for sharing!

@kyptin
Copy link

kyptin commented Dec 9, 2018

You can remove the 'pass a function to itself' weirdness without letfn. The fn form supports a name before the parameter list. For example, ((fn fact [n] (if (zero? n) 1 (* n (fact (dec n))))) 5) returns 120.

@aaronblenkush
Copy link

aaronblenkush commented Jun 25, 2019

(defn delete-files-recursively
  [f1 & [silently]]
  (when (.isDirectory (io/file f1))
    (doseq [f2 (.listFiles (io/file f1))]
      (delete-files-recursively f2 silently)))
  (io/delete-file f1 silently))

@aaronblenkush
Copy link

aaronblenkush commented Jun 28, 2019

Just for fun, here's one that is tail recursive. The fs arg will act as the stack instead of the thread stack, growing as it traverses the file structure in a depth-first post-order search:

(defn tail-recursive-delete
  [& fs]
  (when-let [f (first fs)]
    (if-let [cs (seq (.listFiles (io/file f)))]
      (recur (concat cs fs))
      (do (io/delete-file f)
          (recur (rest fs))))))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment