File System
===========

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

### Easy

Reading and writing files is concise yet flexible.

```kotlin
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.

```kotlin
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:

 * Android API levels <26: [java.io.File](https://developer.android.com/reference/java/io/File)
 * Java and Android API level 26+: [java.nio.file](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/nio/file/FileSystem.html)
 * Linux: [man pages](https://www.kernel.org/doc/man-pages/)
 * UNIX: [stdio.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdio.h.html)
 * Windows: [fileapi.h](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/)
 * Node.js: [file system](https://nodejs.org/api/fs.html)


### 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][fake_fs_concurrency]
   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.)


[fake_fs_concurrency]: https://github.com/square/okio/issues/950
