Skip to main content
These functions manage files and directory trees on disk. On the web, list(), walk(), and sizeRecursively() work on folders from the directory picker, and the experimental origin private file system adds listEntries() and delete(). Call the other functions from nonWebMain or a platform source set.

Usage

nonWebMain

Options

Int
default:"Int.MAX_VALUE"
walk
1 yields only the direct children. Must be positive.
Boolean
default:"false"
createDirectories
true throws if the directory already exists.
Boolean
default:"false"
copyRecursively
true replaces existing files. See Copy a directory tree.
Boolean
default:"true"
delete
true throws if the file doesn’t exist.
Boolean
default:"false"
delete
true empties a directory before removing it.

List a directory

list() returns the direct children and throws on a regular file. It does blocking I/O: on every platform except the web, call it on Dispatchers.IO.

Walk a directory tree

walk() lazily yields every file and subdirectory below a directory, depth-first, without the directory itself:
On a regular file, walk() yields only that file. It is synchronous, like list(): iterate it on Dispatchers.IO.

Get the size of a tree

sizeRecursively() adds up the size of every regular file in the tree, or returns the file’s own size for a regular file. Files whose size is unknown count as 0. It is a suspend function that switches to Dispatchers.IO on every platform except the web. Symbolic links are never followed by walk() or sizeRecursively(), so a link can’t cause an infinite loop: walk() yields the link itself, and sizeRecursively() counts it as 0. This also applies when you call them on a link.

Create directories

nonWebMain
createDirectories() creates the directory and any missing parent. It does nothing if the directory already exists, unless you pass mustCreate = true.

Copy a file

nonWebMain
copyTo() streams the content, so it works when the source size is unknown. An existing destination file is replaced. It throws if the source and destination are the same file, or if the destination folder contains a directory with the source’s name.

Copy a directory tree

copyRecursively() copies a file or a whole directory tree. Unlike copyTo(), the target becomes the new root, not a folder to copy into (as with Kotlin’s File.copyRecursively()):
nonWebMain
  • The copy stops at the first error and leaves the target partially copied: there is no rollback.
  • Symbolic links inside the tree are skipped. Calling it on a link, or copying a directory into itself, throws.
  • It runs on Dispatchers.IO.
With overwrite = true, FileKit can’t tell that an existing target file is the source itself when it is reached through a hard link or a Windows junction. Copying then truncates the source file.

Move a file

nonWebMain
atomicMove() renames the file in a single step and replaces an existing destination file. When the destination is an existing directory, the file moves into it under its own name. Moving across volumes can throw UnsupportedOperationException: use copyTo() then delete() instead.

Delete a file or directory

nonWebMain
Without recursively = true, deleting a non-empty directory throws. Symbolic links (including dangling links) and Windows directory junctions are removed as links: their targets are left untouched.

Platform notes

  • atomicMove() falls back to copy then delete when the source or the destination is a content:// file, and doesn’t support directories.
  • delete() lets the document provider remove the document, with its contents, whatever recursively says.
  • list(), walk(), and sizeRecursively() cost provider queries for each subdirectory, so large trees are slow. Files whose provider doesn’t report a size count as 0.
  • copyRecursively() accepts document trees as a source. As a target, it can create subdirectories only with providers whose document IDs are paths, such as device storage: with other providers, it throws when it needs a new subdirectory. An entry named . or .., containing /, or sharing its name with a sibling makes the copy throw before anything is written. Copying a tree into itself is detected only for providers whose document IDs are paths.
Keep security-scoped access to a picked folder active while you iterate walk(), for example inside folder.withScopedAccess { }. copyRecursively() holds access to the source and the target for the whole copy.
Every reparse point counts as a link, including directory junctions and OneDrive Files On-Demand folders. walk() lists such a folder without its contents, sizeRecursively() doesn’t count it, and copyRecursively() skips it. A copyRecursively() target that reaches the source through a junction isn’t detected as being inside it: the copy doesn’t throw, and it still ends without copying its own output.
list(), walk(), and sizeRecursively() work on folders returned by the directory picker, whose tree is already in memory, and run on the caller’s dispatcher. They throw on origin private file system directories: use listEntries() instead. copyTo(), copyRecursively(), createDirectories(), and atomicMove() are not available. delete() exists only for origin private file system entries. See Files on the web.