1. Introduction
Creating a directory in Kotlin is as easy as it’s in Java. In this tutorial, we’ll look at different ways we can create either single directories or nested directory structures.
2. Creating a Single Directory
First, let’s take a look at the method that’s exposed by java.nio.file.Files to create ./createDirectory directory:
Files.createDirectory(Paths.get("./createDirectory"))
This simple method creates a directory if the provided path can be reached (more on this in a bit) and it doesn’t already exist.
If either of those conditions aren’t met, the createDirectory() method throws IOException:
Files.createDirectory(Paths.get("./createDirectory_2/inner"))
Here, since createDirectory_2 doesn’t yet exist, the creation of inner fails. We’ll take a look at how to handle this issue in the next section.
We have one more method to create a single directory – *File(…).*mkdir():
val resultMkdir: Boolean = File("./mkdir").mkdir()
While Files.createDirectory() throws an exception, mkdir()* instead returns a simple *boolean. true result signifies successful file creation and false result signifies a failure to create a file.
There’s one thing to note here: with the lack of the exception that Files.createDirectory() provides, we can’t be sure of the exact reason mkdir() failed to create a directory. We need to be careful to pick the method that suits our needs best.
Now that we’ve looked at both options to create single directories, let’s see how we can create whole directory trees.
3. Creating Nested Directories
Let’s once again take a look at the method exposed by java.nio.file.Files to create .**/createDirectories/inner directory structure:
Files.createDirectories(Paths.get("./createDirectories/inner"))
As we can see, the usage is exactly the same as in the single directory scenario. The only differences are that it create all intermediary directories and it won’t fail if the directories already exist. In the above example, createDirectories is the intermediary directory, and inner is our target directory.
So while running the Files.createDirectory() for the same path twice would result in an exception, in the case of Files.createDirectories(), there’s no error:
Files.createDirectories(Paths.get("./createDirectories/inner"))
println("Running Files.createDirectories 2nd time does nothing")
Files.createDirectories(Paths.get("./createDirectories/inner"))
Similarly to how createDirectory() has a friend in the form of mkdir(), createDirectories() has a corresponding method in the form of mkdirs():
val resultMkdirs: Boolean = File("./mkdirs/inner").mkdirs()
This method also returns a boolean, signifying either success or failure. Therefore, we once again cannot be sure as to the exact reason why the directory didn’t get created. If we need this information, then using Files.createDirectories() might be a better approach.
4. Path Utility to Create Parent Directories
In this section, we’ll learn about the createParentDirectories()* extension function available in Kotlin *1.9.0. Using this utility, we can create the chain of parent directories for a path when it doesn’t exist.
Let’s imagine that we’ve got the source directory /tmp/source/child that we want to copy recursively at the /tmp/dest/child location:
File("/tmp/source").mkdirs()
File("/tmp/source/child").mkdirs()
val helloWorldFile = File("/tmp/source/child/helloworld.txt")
helloWorldFile.writeText("Hello, World!")
We must note that we’ve created the source directory structure at the /tmp/source/child path. Additionally, we’ve written text to a file at the /tmp/source/child/helloworld.txt path.
Now, let’s see if we can copy the /tmp/source/child path recursively to the /tmp/dest/child path:
assertThrows<NoSuchFileException> {
Path.of("/tmp", "source", "child").copyToRecursively(
Path.of("/tmp", "dest", "child"),
followLinks = false
)
}
Unfortunately, the copy attempt fails, and we get the NoSuchFileException because the location /tmp/dest/child doesn’t exist yet.
Lastly, let’s call the createParentDirectories() method for the /tmp/dest/child path and reattempt the copy operation:
Path.of("/tmp", "dest", "child").createParentDirectories()
Path.of("/tmp", "source", "child").copyToRecursively(
Path.of("/tmp", "dest", "child"),
followLinks = false
)
Assertions.assertTrue(File("/tmp/dest/child").exists())
Assertions.assertTrue(File("/tmp/dest/child/helloworld.txt").exists())
It looks like we got this one right, as the source directory is copied successfully to the target location along with the helloworld.txt file.
5. Conclusion
In this article, we looked at two methods to create either single or nested directories. Files.createDirectory() and Files.createDirectories() are a bit more restrictive but, in return, throw exceptions that give us a better picture of why we might have failed to create the directory.
On the other hand, we have mkdir() and mkdirs() methods, which return a simple boolean instead of throwing an exception. We need to pick our method of choice according to our requirements.
Lastly, we explored the createParentDirectories() extension function for creating a chain of parent directories.
As always, the code from this article is available over on GitHub.