как преобразовать поток scala fs2 в строку?

Я хочу знать, как преобразовать Scala fs2 Stream в строку из примера fs2 github readme:

def converter[F[_]](implicit F: Sync[F]): F[Unit] = {
  val path = "/Users/lorancechen/version_control_project/_unlimited-works/git-server/src/test/resources"

  io.file.readAll[F](Paths.get(s"$path/fs.txt"), 4096)
    .through(text.utf8Decode)
    .through(text.lines)
    .filter(s => !s.trim.isEmpty && !s.startsWith("//"))
    .map(line => fahrenheitToCelsius(line.toDouble).toString)
    .intersperse("\n")
    .through(text.utf8Encode)
    .through(io.file.writeAll(Paths.get(s"$path/fs-output.txt")))
    .compile.drain

}

// at the end of the universe...
val u: Unit = converter[IO].unsafeRunSync()

Как получить результат в String, а не в другой файл?


person LoranceChen    schedule 25.01.2018    source источник
comment
У вас есть поток из String элементов, вы хотите вернуть их коллекцию?   -  person Yuval Itzchakov    schedule 25.01.2018


Ответы (2)


Если вы хотите, чтобы все String элементы работали в вашем потоке, вы можете использовать runFold для его материализации. Упрощенный пример:

def converter[F[_]](implicit F: Sync[F]): F[List[String]] = {
  val path = "/Users/lorancechen/version_control_project/_unlimited-works/git-server/src/test/resources"

  io.file.readAll[F](Paths.get(s"$path/fs.txt"), 4096)
    .through(text.utf8Decode)
    .through(text.lines)
    .filter(s => !s.trim.isEmpty && !s.startsWith("//"))
    .runFold(List.empty[String]) { case (acc, str) => str :: acc }
}

А потом:

val list: List[String] = converter[IO].unsafeRunSync()
person Yuval Itzchakov    schedule 25.01.2018
comment
спасибо, работает хорошо. Кроме того, последняя версия fs2 (v0.10.0-M11) рекомендует использовать compile.fold instand. - person LoranceChen; 25.01.2018
comment
Это не подходящее решение для более поздних версий. .compile.to(List) для объединения каждого элемента в список или .compile.string для преобразования непосредственно в единственную строку. Как и более свежий ответ ниже. - person ChristopherDavenport; 28.04.2021

Если у вас есть Stream[F, String], вы можете вызвать .compile.string, чтобы преобразовать поток в F[String].

val s: Stream[IO, String] = ???
val io: IO[String] = s.compile.string
val str: String = io.unsafeRunSync()
person Jasper-M    schedule 28.11.2019