Skip to content

Instantly share code, notes, and snippets.

@edw
Last active November 12, 2021 20:31
Show Gist options
  • Select an option

  • Save edw/5128978 to your computer and use it in GitHub Desktop.

Select an option

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))))

ghost commented Apr 8, 2015

Copy link
Copy Markdown

Fantastic. This is very useful on Windows when you can't delete insane directory hierarchies because of the MAX_PATH limitation. Just fire a "lein repl", load your script and (delete-recursively "insane/path").
Thanks a lot

@LouisBurke

Copy link
Copy Markdown

Brilliant.

@erdos

erdos commented Jan 3, 2017

Copy link
Copy Markdown

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

ulsa commented May 18, 2017

Copy link
Copy Markdown

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
Copy Markdown

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
Copy Markdown

Nice, thanks for sharing!

@kyptin

kyptin commented Dec 9, 2018

Copy link
Copy Markdown

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

aaronblenkush commented Jun 25, 2019

Copy link
Copy Markdown
(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

aaronblenkush commented Jun 28, 2019

Copy link
Copy Markdown

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