Потоковое CSV с помощью akka-http в Scala

Я очень новичок в akka-http, и я хотел бы передать поток csv с произвольным числом строк.

Например, я хотел бы вернуть:

a,1
b,2
c,3

со следующим кодом

implicit val actorSystem = ActorSystem("system")
implicit val actorMaterializer = ActorMaterializer()

val map = new mutable.HashMap[String, Int]()
map.put("a", 1)
map.put("b", 2)
map.put("c", 3)
val `text/csv` = ContentType(MediaTypes.`text/csv`, `UTF-8`)
val route =
  path("test") {
    complete {
      HttpEntity(`text/csv`, ??? using map)
    }
  }
Http().bindAndHandle(route,"localhost",8080)

Спасибо за вашу помощь

РЕДАКТИРОВАТЬ: Благодаря Рамону J Romero y Vigil

package test


import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.HttpCharsets.`UTF-8`
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.stream._
import akka.util.ByteString

import scala.collection.mutable

object Test{

  def main(args: Array[String]) {

    implicit val actorSystem = ActorSystem("system")
    implicit val actorMaterializer = ActorMaterializer()

    val map = new mutable.HashMap[String, Int]()
    map.put("a", 1)
    map.put("b", 2)
    map.put("c", 3)

    val mapStream = Stream.fromIterator(() => map.toIterator)
      .map((k: String, v: Int) => s"$k,$v")
      .map(ByteString.apply)
    val `text/csv` = ContentType(MediaTypes.`text/csv`, `UTF-8`)
    val route =
      path("test") {
        complete {
          HttpEntity(`text/csv`, mapStream)
        }
      }
    Http().bindAndHandle(route, "localhost", 8080)

  }
}

С этим кодом у меня есть две ошибки компиляции:

Error:(29, 28) value fromIterator is not a member of object scala.collection.immutable.Stream
val mapStream = Stream.fromIterator(() => map.toIterator)

Error:(38, 11) overloaded method value apply with alternatives:
  (contentType: akka.http.scaladsl.model.ContentType,file: java.io.File,chunkSize: Int)akka.http.scaladsl.model.UniversalEntity <and>
  (contentType: akka.http.scaladsl.model.ContentType,data: akka.stream.scaladsl.Source[akka.util.ByteString,Any])akka.http.scaladsl.model.HttpEntity.Chunked <and>
  (contentType: akka.http.scaladsl.model.ContentType,data: akka.util.ByteString)akka.http.scaladsl.model.HttpEntity.Strict <and>
  (contentType: akka.http.scaladsl.model.ContentType,bytes: Array[Byte])akka.http.scaladsl.model.HttpEntity.Strict <and>
  (contentType: akka.http.scaladsl.model.ContentType.NonBinary,string: String)akka.http.scaladsl.model.HttpEntity.Strict
 cannot be applied to (akka.http.scaladsl.model.ContentType.WithCharset, List[akka.util.ByteString])
          HttpEntity(`text/csv`, mapStream)

Я использовал Список кортежей, чтобы обойти первую проблему (но я не знаю, как передавать карту в Scala). Не знаю, во-вторых, Спасибо за вашу помощь.

(Я использую scala 2.11.8)

1 ответ

Использовать apply функция в HttpEntity это занимает Source[ByteString,Any], Приложение создает Chunked юридическое лицо. Вы можете прочитать ваш файл, используя код на основе документации для потокового ввода-вывода файла, используя akka stream Source:

import akka.stream.scaladsl._

val file = Paths.get("yourFile.csv")

val entity = HttpEntity(`txt/csv`, FileIO.fromPath(file))

Поток разбит ваш файл на размеры чанка, по умолчанию в настоящее время установлено значение 8192.

Для потоковой передачи карты, которую вы создали, вы можете использовать похожий трюк:

val mapStream = Source.fromIterator(() => map.toIterator)
                      .map( (k : String, v : Int) => s"$k,$v" )
                      .map(ByteString.apply)

val mapEntity = HttpEntity(`test/csv`, mapStream)
Другие вопросы по тегам