Skip to content

Latest commit

 

History

History
145 lines (104 loc) · 4.13 KB

File metadata and controls

145 lines (104 loc) · 4.13 KB
title File operations
description Find, copy, move/rename and delete files
date 2019-10-31 17:00:00 -0700
layout default

Pre-filing

We'll see some simple one line examples on operations on files themselves without modifying contents. We'll just use standard Java and Kotlin classes. Steps before your start at Works on my machine and to import stuff do: import java.io.*

List folders and files

First step is always to create a File that represents a path to a file or folder. To create one pass a String with the path. E.g. to make a File out of your home folder:

val home = File(System.getProperty("user.home"))

The following will list names of all non-hidden files only in your home folder without going into subfolders:

home.walk()
    .maxDepth(1)
    .filter { f -> f.isFile }
    .filter { f -> !f.isHidden }
    .forEach { f -> print("${f.name}\n") }

home.walk() will perform depth-first traversal. You can use home.walkBottomUp() for breadth-first.

To recursively search for files by name and type and get the absolutePath, try the following:

home.walk()
    .filter { f -> f.isFile }
    .filter { f -> f.nameWithoutExtension == "someText"}
    .filter { f -> f.extension =="txt"}
    .first()
    .absolutePath
    

Or you could filter by f.name == "someText.txt"" for same result.

Note that with first() you can get a new File representing a folder, and use it as a basis for future searches:

val docs = home.walk()
    .filter { f -> f.isDirectory }
    .filter { f -> f.name == "Documents"}
    .first()

You may list folders sorted by name like this:

home.walk()
    .maxDepth(1)
    .filter { f -> f.isDirectory }
    .sortedBy { f -> f.name }
    .forEach { f -> print("${f.name}\n") }

Note that the home folder, the root of this traversal, is included.

We may want to filter files per the parent folder. For example count Kotlin source files in a multi-project source code folder. We expect them to be in folders like: src/main/kotlin.

home.walk()
    .filter { f -> f.isFile }
    .filter { f -> f.extension == "kt"}
    .filter { f -> f.parent.endsWith("src/main/kotlin")}
    .count()

Size matters

To get the size of a file:

someFile.length()

The above is not useful for folders. To get the size of all files in a folder we need to iterate over them:

home.walk()
    .maxDepth(1)
    .filter { f -> f.isFile }
    .map { f -> f.length() }
    .sum()

From any file, you can get usage and size information for the whole disk:

home.freeSpace
home.usableSpace
home.totalSpace

Expect usableSpace to be less than freeSpace

Modify files

To create a new empty folder:

val someFolder = docs.resolve("someFolder")
someFolder.mkdir()

To create a new empty file:

val someText = someFolder.resolve("someText.txt")
someText.createNewFile()

you can chain two resolve calls, but you have to create a folder before creating a file within it.

We can rename/move a file by:

val movedFile = docs.resolve("someFileMovedToDocs.txt")
someText.renameTo(movedFile)

This method take a File argument and since the file is under a different folder, it was moved as well as renamed. So it's similar to Unix mv command. If you now type someText to inspect the variable, you'll see it still refers to original path Documents/someFolder/someText.txt that no longer exists. Consequently, if you try to rename someText again it will fail and return kotlin.Boolean = false.

If we wanted to copy instead, keeping the original file:

val copiedFile = someText.copyTo(docs.resolve("someFolder/copyOfSomeText.txt"))

which, unlike previous methods, returns a File instead of boolean.

If you regret copying the file, to get rid of it:

copiedFile.delete()