File system utilities. This library can used from:
- Clojure on the JVM - we support Clojure 1.10.3 and above on Java 11 and above.
- babashka - it has been a built-in library since babashka v0.2.9.
Babashka is a scripting utility. It's convenient to have cross platform file
system utilities available for scripting. The namespace clojure.java.io
already offers a bunch of useful features, but it predates java.nio. The nio
package isn't that nice to use from Clojure and this library should help with
that.
The main inspirations for this library are clojure.java.io, clj-commons/fs and corasaurus-hex/fs.
See API.md.
(require '[babashka.fs :as fs])
(fs/directory? ".") ;;=> trueThe glob function takes a root path and a pattern. The pattern is interpreted
as documented
here.
(map str (fs/glob "." "**{.clj,cljc}"))Output:
("project.clj" "test/babashka/fs_test.clj" "src/babashka/fs.cljc")The function exec-paths returns all entries from PATH as Paths. To search
all these directories for an executable, e.g. java, you can combine it with
list-dirs which searches files directly in the directories using an (optional)
glob pattern:
(str (first (filter fs/executable? (fs/list-dirs (filter fs/exists? (fs/exec-paths)) "java"))))
"/Users/borkdude/.jenv/versions/11.0/bin/java"For convenience, the above use case is also supported using the which function:
(str (fs/which "java"))
"/Users/borkdude/.jenv/versions/11.0/bin/java"Behaviour can vary on different file systems and OSes. If you uncover some interesting nuance, please let us know.
The underlying JDK file APIs (and, by extension, babashka.fs) typically consider an empty-string path "" to be the current working directory. This means that (fs/list-dir "") is functionally equivalent to (fs/list-dir ".").
On Linux and macOS you can often optionally specify :posix-file-permissions.
For newly created files and directories, these permissions are affected by your configured umask.
For example, let's say your umask masks out the others-write permission:
$ umask -S
u=rwx,g=rwx,o=rxNotice that others-write, even though specified on creation, is masked out by umask:
(fs/create-file "afile" {:posix-file-permissions "rwxrwxrwx"})
;; umask affected resulting permissions of new files
(-> (fs/posix-file-permissions "afile") (fs/posix->str))
;; => "rwxrwxr-x"This applies only to newly created files and directories. You can explicitly set permissions on existing files and directories:
(fs/create-dir "adir" {:posix-file-permissions "rwxrwxrwx"})
;; umask affected resulting permissions of new dirs
(-> (fs/posix-file-permissions "adir") (fs/posix->str))
;; => "rwxrwxr-x"
;; but you can explicitly override permissions on existing file & dirs like so:
(fs/set-posix-file-permissions "adir" "rwxrwxrwx")
(-> (fs/posix-file-permissions "adir") (fs/posix->str))
;; => "rwxrwxrwx"This is the underlying behaviour the JDK file APIs, see Setting Initial Permissions in JavaDocs. Babashka fs, as a light wrapper, reflects this behaviour.
Depending on which OS and JDK version you are running, creation-time might return unexpected results.
As of this writing, our testing has revealed:
- Windows - returns creation time as expected
- macOS - returns creation time as expected
- Linux - returns modified time before JDK 17, otherwise returns creation time as expected
See JDK-8316304.
Depending on which OS and JDK version you are running, set-creation-time might not do what you would expect.
As of this writing, our testing has revealed:
- Windows - sets creation time as expected
- macOS
- after Java 17 sets creation time as expected, otherwise seems to have no effect
- otherwise has no effect
- Linux - seems to have no effect
See JDK-8151430
Many babashka.fs functions accept the :nofollow-links option.
These functions will follow symbolic links unless you pass in {:nofollow-links true}.
Some babashka.fs functions accept the :follow-links option.
These functions will not follow symbolic links unless you pass in {:follow-links true}.
To run all tests
$ bb test
You can also use cognitect test-runner options, for example, to run a single test:
bb test --var babashka.fs-test/walk-test
Note
To allow us to contrive isolated file system scenarios, tests are always run from the scratch current working directory ./target/test-cwd.
To fire up a REPL when working on these tests, run:
bb dev
Tip
The .nrepl-port file will be generated under ./target/test-cwd/, so you'll have to type the REPL port in manually when connecting.
This project generates API docs with quickdoc, to regenerate API.md:
shell quickdoc
Copyright © 2020-2025 Michiel Borkent
Distributed under the EPL License, same as Clojure. See LICENSE.