Skip to content

Commit

Permalink
Syntactic sugar for writing files
Browse files Browse the repository at this point in the history
  • Loading branch information
squarejesse committed Jan 6, 2021
1 parent 61913ce commit c60f820
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 0 deletions.
103 changes: 103 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,108 @@ fun decryptAesToByteString(file: File, key: ByteArray, iv: ByteArray): ByteStrin
}
```

File System Examples
--------------------

Okio's recently gained a multiplatform file system API. These examples work on JVM, native, and
Node.js platforms. In the examples below `fileSystem` is an instance of [FileSystem] such as
`FileSystem.SYSTEM` or `FakeFileSystem`.

Read all of `readme.md` as a string:

```
val path = "readme.md".toPath()
val entireFileString = fileSystem.read(path) {
readUtf8()
}
```

Read all of `thumbnail.png` as a [ByteString][3]:

```
val path = "thumbnail.png".toPath()
val entireFileByteString = fileSystem.read(path) {
readByteString()
}
```

Read all lines of `/etc/hosts` into a `List<String>`:

```
val path = "/etc/hosts".toPath()
val allLines = fileSystem.read(path) {
generateSequence { readUtf8Line() }.toList()
}
```

Read the prefix of `index.html` that precedes the first `<html>` substring:

```
val path = "index.html".toPath()
val untilHtmlTag = fileSystem.read(path) {
val htmlTag = indexOf("<html>".encodeUtf8())
if (htmlTag != -1L) readUtf8(htmlTag) else null
}
```

Write `readme.md` as a string:

```
val path = "readme.md".toPath()
fileSystem.write(path) {
writeUtf8(
"""
|Hello, World
|------------
|
|This is a sample file.
|""".trimMargin()
)
}
```

Write `data.bin` as a [ByteString][3]:

```
val path = "data.bin".toPath()
fileSystem.write(path) {
val byteString = "68656c6c6f20776f726c640a".decodeHex()
write(byteString)
}
```

Write `readme.md` from a `List<String>`:

```
val path = "readme.md".toPath()
val lines = listOf(
"Hello, World",
"------------",
"",
"This is a sample file.",
""
)
fileSystem.write(path) {
for (line in lines) {
writeUtf8(line)
writeUtf8("\n")
}
}
```

Generate `binary.txt` programmatically:

```
val path = "binary.txt".toPath()
fileSystem.write(path) {
for (i in 1 until 100) {
writeUtf8("$i ${i.toString(2)}")
writeUtf8("\n")
}
}
```


Releases
--------

Expand Down Expand Up @@ -1049,6 +1151,7 @@ License
[WriteFileKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/WriteFile.kt
[ExploreCharsets]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/ExploreCharsets.java
[ExploreCharsetsKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/ExploreCharsets.kt
[FileSystem]: https://square.github.io/okio/2.x/okio/okio/-file-system/index.html
[GoldenValue]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/GoldenValue.java
[GoldenValueKt]: https://github.com/square/okio/blob/master/samples/src/jvmMain/kotlin/okio/samples/GoldenValue.kt
[BitmapEncoder]: https://github.com/square/okio/blob/master/samples/src/jvmMain/java/okio/samples/BitmapEncoder.java
Expand Down
20 changes: 20 additions & 0 deletions okio/src/commonMain/kotlin/okio/FileSystem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,16 @@ abstract class FileSystem {
@Throws(IOException::class)
abstract fun source(file: Path): Source

/**
* Creates a source to read [file], executes [readerAction] to read it, and then closes the
* source. This is a compact way to read the contents of a file.
*/
inline fun <T> read(file: Path, readerAction: BufferedSource.() -> T): T {
return source(file).buffer().use {
it.readerAction()
}
}

/**
* Returns a sink that writes bytes to [file] from beginning to end. If [file] already exists it
* will be replaced with the new data.
Expand All @@ -164,6 +174,16 @@ abstract class FileSystem {
@Throws(IOException::class)
abstract fun sink(file: Path): Sink

/**
* Creates a sink to write [file], executes [writerAction] to write it, and then closes the sink.
* This is a compact way to write a file.
*/
inline fun <T> write(file: Path, writerAction: BufferedSink.() -> T): T {
return sink(file).buffer().use {
it.writerAction()
}
}

/**
* Returns a sink that appends bytes to the end of [file], creating it if it doesn't already
* exist.
Expand Down
27 changes: 27 additions & 0 deletions okio/src/commonTest/kotlin/okio/AbstractFileSystemTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,21 @@ abstract class AbstractFileSystemTest(
source.close()
}

@Test
fun readPath() {
val path = base / "read-path"
val string = "hello, read with a Path"
path.writeUtf8(string)

val result = fileSystem.read(path) {
assertEquals("hello", readUtf8(5))
assertEquals(", read with ", readUtf8(12))
assertEquals("a Path", readUtf8())
return@read "success"
}
assertEquals("success", result)
}

@Test
fun fileSink() {
val path = base / "file-sink"
Expand All @@ -143,6 +158,18 @@ abstract class AbstractFileSystemTest(
assertEquals("hello, world!", path.readUtf8())
}

@Test
fun writePath() {
val path = base / "write-path"
val content = fileSystem.write(path) {
val string = "hello, write with a Path"
writeUtf8(string)
return@write string
}
assertTrue(path in fileSystem.list(base))
assertEquals(content, path.readUtf8())
}

@Test
fun appendingSinkAppendsToExistingFile() {
val path = base / "appending-sink-appends-to-existing-file"
Expand Down

0 comments on commit c60f820

Please sign in to comment.