将 Flow<Byte> 转换为 Flow<String> 在 Kotlin 中

huangapple go评论76阅读模式
英文:

Transforming a Flow<Byte> to a Flow<String> in Kotlin

问题

考虑我有一个UTF-8字节的_cold_源(例如:从磁盘上读取文件或HTTP响应的主体),以Flow&lt;Byte&gt;的形式。我如何将上述源转换为字符串的_flow_?

换句话说,我希望以下行为:

  1. /*
  2. * 一个多行字符串,不以换行字符结尾。
  3. */
  4. val string = &quot;&quot;&quot;
  5. first line
  6. 第二行
  7. третья строка
  8. &quot;&quot;&quot;.trimIndent()
  9. assertNotEquals(&#39;\n&#39;, string.last())
  10. assertEquals(2, string.asSequence().count { it == &#39;\n&#39; })
  11. val source: Flow&lt;Byte&gt; = string.toByteArray().asSequence().asFlow()
  12. val transformed: Flow&lt;String&gt; = TODO()
  13. val target = runBlocking {
  14. transformed.toList(mutableListOf()).toTypedArray()
  15. }
  16. assertArrayEquals(
  17. arrayOf(&quot;first line&quot;, &quot;第二行&quot;, &quot;третья строка&quot;),
  18. target
  19. )

作为额外限制,这是一个Kotlin/JS项目,因此无法使用java.io API。

英文:

Consider I have a cold source of UTF-8 bytes (e. g.: reading a file on disk, or the body of an HTTP response), in a form of a Flow&lt;Byte&gt;. How do I convert the above source to a flow of strings?

In other words, I want the following behaviour:

  1. /*
  2. * A multi-line string, not terminated with a newline character.
  3. */
  4. val string = &quot;&quot;&quot;
  5. first line
  6. 第二行
  7. третья строка
  8. &quot;&quot;&quot;.trimIndent()
  9. assertNotEquals(&#39;\n&#39;, string.last())
  10. assertEquals(2, string.asSequence().count { it == &#39;\n&#39; })
  11. val source: Flow&lt;Byte&gt; = string.toByteArray().asSequence().asFlow()
  12. val transformed: Flow&lt;String&gt; = TODO()
  13. val target = runBlocking {
  14. transformed.toList(mutableListOf()).toTypedArray()
  15. }
  16. assertArrayEquals(
  17. arrayOf(&quot;first line&quot;, &quot;第二行&quot;, &quot;третья строка&quot;),
  18. target
  19. )

As an extra restriction, this is a Kotlin/JS project, so java.io APIs can't be used.

答案1

得分: 1

以下是翻译好的代码部分:

  1. fun Flow<Byte>.decodeToString(): Flow<String> =
  2. flow {
  3. val buffer: MutableList<Byte> = arrayListOf()
  4. collect { value ->
  5. when (value) {
  6. /*
  7. * Ignore.
  8. */
  9. '\r'.code.toByte() -> Unit
  10. '\n'.code.toByte() -> {
  11. emit(buffer)
  12. buffer.clear()
  13. }
  14. else -> buffer.add(value)
  15. }
  16. }
  17. if (buffer.isNotEmpty()) {
  18. emit(buffer)
  19. }
  20. }
  21. .map(Collection<Byte>::toByteArray)
  22. .map(ByteArray::decodeToString)

上面的 ArrayList<Byte> 可以替换为 _okio_ 中的 okio.Buffer_kotlinx-io_ 中的 kotlinx.io.core.BytePacketBuilder,例如:

  1. import kotlinx.coroutines.flow.Flow
  2. import kotlinx.coroutines.flow.flow
  3. import okio.Buffer
  4. fun Flow<Byte>.decodeToString(): Flow<String> =
  5. flow {
  6. val buffer = Buffer()
  7. collect { value ->
  8. when (value) {
  9. /*
  10. * Ignore.
  11. */
  12. '\r'.code.toByte() -> Unit
  13. '\n'.code.toByte() -> {
  14. emit(buffer.readUtf8())
  15. buffer.clear()
  16. }
  17. else -> buffer.writeByte(value.toInt())
  18. }
  19. }
  20. if (buffer.size > 0) {
  21. emit(buffer.readUtf8())
  22. }
  23. }
英文:

Eventually, I came up with the following solution:

  1. fun Flow&lt;Byte&gt;.decodeToString(): Flow&lt;String&gt; =
  2. flow {
  3. val buffer: MutableList&lt;Byte&gt; = arrayListOf()
  4. collect { value -&gt;
  5. when (value) {
  6. /*
  7. * Ignore.
  8. */
  9. &#39;\r&#39;.code.toByte() -&gt; Unit
  10. &#39;\n&#39;.code.toByte() -&gt; {
  11. emit(buffer)
  12. buffer.clear()
  13. }
  14. else -&gt; buffer.add(value)
  15. }
  16. }
  17. if (buffer.isNotEmpty()) {
  18. emit(buffer)
  19. }
  20. }
  21. .map(Collection&lt;Byte&gt;::toByteArray)
  22. .map(ByteArray::decodeToString)

The ArrayList&lt;Byte&gt; above can be replaced with either okio.Buffer from okio or kotlinx.io.core.BytePacketBuilder from kotlinx-io, e.g.:

  1. import kotlinx.coroutines.flow.Flow
  2. import kotlinx.coroutines.flow.flow
  3. import okio.Buffer
  4. fun Flow&lt;Byte&gt;.decodeToString(): Flow&lt;String&gt; =
  5. flow {
  6. val buffer = Buffer()
  7. collect { value -&gt;
  8. when (value) {
  9. /*
  10. * Ignore.
  11. */
  12. &#39;\r&#39;.code.toByte() -&gt; Unit
  13. &#39;\n&#39;.code.toByte() -&gt; {
  14. emit(buffer.readUtf8())
  15. buffer.clear()
  16. }
  17. else -&gt; buffer.writeByte(value.toInt())
  18. }
  19. }
  20. if (buffer.size &gt; 0) {
  21. emit(buffer.readUtf8())
  22. }
  23. }

huangapple
  • 本文由 发表于 2023年2月8日 17:08:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/75383429.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定