Skip to content

File System

Okio’s file system is designed to be easy, testable, multiplatform, and efficient.

Easy

Reading and writing files is concise yet flexible.

val path = "README.md".toPath()

val readmeContent = FileSystem.SYSTEM.read(path) {
  readUtf8()
}

val updatedContent = readmeContent.replace("red", "blue")

FileSystem.SYSTEM.write(path) {
  writeUtf8(updatedContent)
}

Testable

It’s easy to swap out the real file system with a fake. This makes tests run faster and more reliably.

val fileSystem = FakeFileSystem()
val userHome = "/Users/sandy".toPath()
val gitConfig = userHome / ".gitconfig"

fileSystem.createDirectories(userHome)
val original = """
    |[user]
    |  email = sandy@example.com
    |""".trimMargin()
fileSystem.write(gitConfig) { writeUtf8(original) }

GitConfigFixer(fileSystem).fix(userHome)

val expected = """
  |[user]
  |  email = sandy@example.com
  |[diff]
  |  renames = true
  |  indentHeuristic = on
  """.trimIndent()
assertEquals(expected, fileSystem.read(gitConfig) { readUtf8() })

With ForwardingFileSystem you can easily inject faults to confirm your program is graceful even when the user’s disk fills up.

Multiplatform

Okio’s Path class supports Windows-style (like C:\autoexec.bat) and UNIX-style paths (like /etc/passwd). It supports manipulating Windows paths on UNIX, and UNIX paths on Windows.

The system FileSystem abstracts over these platform APIs:

Efficient

Read and write operations integrate with Okio buffers to reduce the number of system calls.

It exposes high-level operations like atomicMove() and metadata to get the OS to do all the work when appropriate.

Known Issues

Okio’s implementation is constrained by the capabilities its underlying APIs. This page is an overview of these limitations.

All Platforms

  • There are no APIs for file permissions, watches, volume management, memory mapping, or locking.
  • Paths that cannot be represented as UTF-8 strings are unsupported. The underlying APIs that Okio calls through, including java.io.File, all treat paths as strings.

Kotlin/JVM

On Android, API level less than 26:

  • Creating and accessing symlinks is unsupported.

On Windows:

  • FileSystem.atomicMove() fails if the target file already exists.

Kotlin/Native

  • FakeFileSystem does not support concurrent use. We are holding off on this until the upcoming memory model is released.

On Windows:

  • Creating and accessing symlinks is unsupported.

Kotlin/JS

  • NodeJsFileSystem’s source() and sink() cannot access UNIX pipes.
  • Instead of returning null, NodeJsFileSystem.metadataOrNull() throws IOException if the path is invalid. (In the Node.js API there’s no mechanism to differentiate between a failure to read a valid path and a rejection of an invalid path.)