{"id":16482084,"url":"https://github.com/bod/kotlinx-io-explorations","last_synced_at":"2025-10-04T13:45:39.409Z","repository":{"id":180721776,"uuid":"665496506","full_name":"BoD/kotlinx-io-explorations","owner":"BoD","description":"Kotlinx-io explorations","archived":false,"fork":false,"pushed_at":"2023-07-12T14:58:04.000Z","size":73,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-28T21:45:09.994Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BoD.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-07-12T10:32:42.000Z","updated_at":"2023-07-12T20:04:38.000Z","dependencies_parsed_at":"2023-07-13T02:01:00.827Z","dependency_job_id":null,"html_url":"https://github.com/BoD/kotlinx-io-explorations","commit_stats":null,"previous_names":["bod/kotlinx-io-explorations"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/BoD/kotlinx-io-explorations","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BoD%2Fkotlinx-io-explorations","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BoD%2Fkotlinx-io-explorations/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BoD%2Fkotlinx-io-explorations/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BoD%2Fkotlinx-io-explorations/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BoD","download_url":"https://codeload.github.com/BoD/kotlinx-io-explorations/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BoD%2Fkotlinx-io-explorations/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278322183,"owners_count":25967873,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T13:09:34.051Z","updated_at":"2025-10-04T13:45:39.168Z","avatar_url":"https://github.com/BoD.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kotlinx-io explorations\n\nThis repository contains some explorations of the [Kotlinx-io](https://github.com/Kotlin/kotlinx-io) library.\n\n## Context\n\n[Okio](https://github.com/square/okio) has been a go-to IO library for Java and Kotlin, in particular Kotlin Multiplatform, for a while. It\nis a mature and stable library.\nRecently, JetBrains have released version `0.2.0` of their Kotlinx-io library, which is based on/inspired by Okio.\n\nI have no specific insight into the creation of kotlinx-io, but my understanding is that one goal is to have this more of a \"standard\"\nKotlin library, maintained by JetBrains, rather than a third-party library. If this becomes a widely adopted library, this will help library\nauthors with deciding what IO library to use / expose in their APIs (i.e. having a Kotlin/KotlinX dependency is less controversial than\nusing a third-party one - arguably).\n\n## API\n\nThe API of Kotlinx-io is very analogous to Okio, but not identical.\n\nFrom what I can tell, the way this was done is that the main classes from Okio where copied over to Kotlinx-io, and then the API was tweaked\nto either be more idiomatic Kotlin, or improve naming. I assume Java compat is also less of a priority.\n\nThe 4 main classes from Okio are there: `Buffer`, `Source`, `Sink` and `ByteString`, with mostly the exact same API.\n\nTo have an example, in this project is a little CLI app that takes 2 files as arguments and will read the first one and output it to the\nsecond one, with a line number prefixed for each line. It will also print the prefixed lines to the console.\n\nHere's an annotated diff of both versions:\n\n```\npackage com.example.kotlinxiotest.okio                          |       package com.example.kotlinxiotest.kotlinxio\n                                                                        \nimport okio.Buffer                                              |       import kotlinx.io.Buffer                                        | Package differences\nimport okio.FileSystem                                          |       import kotlinx.io.RawSink\nimport okio.Path.Companion.toPath                               |       import kotlinx.io.buffered\nimport okio.Sink                                                |       import kotlinx.io.files.Path\nimport okio.Timeout                                             |       import kotlinx.io.files.sink\nimport okio.buffer                                              |       import kotlinx.io.files.source\nimport okio.use                                                 |       import kotlinx.io.readLine\n                                                                \u003e       import kotlinx.io.readString\n                                                                \u003e       import kotlinx.io.writeString\n                                                                        \nclass OkioPrefixer(                                             |       class KotlinxIoPrefixer(\n  private val source: String,                                             private val source: String,\n  private val destination: String,                                        private val destination: String,\n) {                                                                     ) {\n  fun prefix() {                                                          fun prefix() {\n    val sourcePath = source.toPath()                            |           val sourcePath = Path(source)                               | Different ways of getting a Source/Sink from a Path. Note: Path is experimental in kotlinx-io\n    val sourceSource = systemFileSystem.source(sourcePath       |           val sourceSource = sourcePath.source()\n      .buffer()                                                 |             .buffered()\n    val destinationPath = destination.toPath()                  |           val destinationPath = Path(destination)\n    val destinationSink = systemFileSystem.sink(destinati       |           val destinationSink = destinationPath.sink()\n    val teeSink = TeeSink(destinationSink, StdoutSink())                    val teeSink = TeeSink(destinationSink, StdoutSink())\n      .buffer()                                                 |             .buffered()                                               | buffer() renamed to bufferred()\n                                                                \u003e           @OptIn(ExperimentalStdlibApi::class)                        | Okio has its own .use, whereas with kotlinx-io we use the stdlib one (which is experimental) \n    teeSink.use { sink -\u003e                                                   teeSink.use { sink -\u003e\n      sourceSource.use { source -\u003e                                            sourceSource.use { source -\u003e\n        var lineIndex = 1                                                       var lineIndex = 1\n        var line: String?                                                       var line: String?\n        while (true) {                                                          while (true) {                                          \n          line = source.readUtf8Line() ?: break                 |                 line = source.readLine() ?: break                     | readUtf8Line() renamed to readLine()\n          val lineIndexFormatted = lineIndex++.toString()                         val lineIndexFormatted = lineIndex++.toString()\n          sink.writeUtf8(lineIndexFormatted)                    |                 sink.writeString(lineIndexFormatted)                  | writeUtf8 renamed to writeString\n          sink.writeByte(' '.code)                              |                 sink.writeByte(' '.code.toByte())                     | writeByte() now takes a Byte, not an Int\n          sink.writeUtf8(line)                                  |                 sink.writeString(line)\n          sink.writeByte('\\n'.code)                             |                 sink.writeByte('\\n'.code.toByte())\n        }                                                                       }\n      }                                                                       }\n    }                                                                       }\n  }                                                                       }\n}                                                                       }\n                                                                        \nclass TeeSink(                                                          class TeeSink(\n  private val a: Sink,                                          |         private val a: RawSink,                                       | Okio's Sink (top level interface) has been renamed to RawSink, while BufferedSink (implements Sink) has been renamed to Sink (implements RawSink)\n  private val b: Sink,                                          |         private val b: RawSink,\n) : Sink {                                                      |       ) : RawSink {\n  override fun close() {                                                  override fun close() {\n    a.close()                                                               a.close()\n    b.close()                                                               b.close()\n  }                                                                       }\n                                                                        \n  override fun flush() {                                                  override fun flush() {\n    a.flush()                                                               a.flush()\n    b.flush()                                                               b.flush()\n  }                                                                       }\n                                                                        \n  override fun write(source: Buffer, byteCount: Long) {                   override fun write(source: Buffer, byteCount: Long) {\n    val peek = Buffer().apply { source.copyTo(this, 0, by                   val peek = Buffer().apply { source.copyTo(this, 0, by\n    a.write(peek, byteCount)                                                a.write(peek, byteCount)\n    b.write(source, byteCount)                                              b.write(source, byteCount)\n  }                                                                       }\n                                                                \u003c       \n  override fun timeout(): Timeout {                             \u003c                                                                       | No more timeouts in kotlinx-io\n    return Timeout.NONE                                         \u003c       \n  }                                                             \u003c       \n}                                                                       }\n                                                                        \nclass StdoutSink : Sink {                                       |       class StdoutSink : RawSink {\n  override fun close() {}                                                 override fun close() {}\n                                                                        \n  override fun flush() {}                                                 override fun flush() {}\n                                                                        \n  override fun write(source: Buffer, byteCount: Long) {                   override fun write(source: Buffer, byteCount: Long) {\n    print(source.readUtf8(byteCount))                           |           print(source.readString(byteCount))\n  }                                                                       }\n                                                                \u003c       \n  override fun timeout(): Timeout {                             \u003c       \n    return Timeout.NONE                                         \u003c       \n  }                                                             \u003c       \n}                                                                       }\n                                                                \u003c       \nexpect val systemFileSystem: FileSystem                         \u003c                                                                       | Okio uses FileSystem to abstract file operations and get Sink/Source from a Path. Kotlinx-io uses Path directly.\n                                                                \u003c\n```\n\n## Missing parts\n\nFrom what I can tell, Kotlinx-io will not be a complete replacement for Okio, or at least it is not yet for now. Here are a few things that\nare in Okio but not in Kotlinx-io:\n\n- FileSystem\n- Pipe\n- Compression (Deflater, Inflater, Gzip)\n- Hashing (md5, sha1, etc.)\n- Encryption/Decryption (Cipher)\n- Getting a Source/Sink from a Socket\n\n## Targets\n\nBoth libraries target the JVM, JS (Node, Browser) and Native (Apple, Linux, Windows, Android).\n\nWASM:\n\n- Okio: support is ongoing: https://github.com/square/okio/issues/1203\n- Kotlinx-io: not supported yet: https://github.com/Kotlin/kotlinx-io/issues/164\n\n\n## TODO\n\n- Look at how easy it would be to have Okio \u003c-\u003e kotlinx-io adapters\n- Benchmarks?\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbod%2Fkotlinx-io-explorations","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbod%2Fkotlinx-io-explorations","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbod%2Fkotlinx-io-explorations/lists"}