-
-
Save edw/5128978 to your computer and use it in GitHub Desktop.
(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)))) |
Brilliant.
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)))
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
.
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))))
Nice, thanks for sharing!
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
.
(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))
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))))))
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