私はcsvファイルを読んでいます。これを行うためにAkka Streamsを使用して、各行で実行するアクションのグラフを作成できるようにしています。次のおもちゃのサンプルを実行しました。
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem("MyAkkaSystem")
implicit val materializer = ActorMaterializer()
val source = akka.stream.scaladsl.Source.fromIterator(Source.fromFile("a.csv").getLines)
val sink = Sink.foreach(println)
source.runWith(sink)
}
2つのSource
タイプは、私には簡単にはいかない。これは慣用的ですか、これを書くためのより良い方法はありますか?
実際、akka-streams
はファイルから直接読み取る関数を提供します。
FileIO.fromPath(Paths.get("a.csv"))
.via(Framing.delimiter(ByteString("\n"), 256, true).map(_.utf8String))
.runForeach(println)
ここで、runForeach
メソッドは行を出力することです。これらの行を処理するための適切なSink
がある場合は、この関数の代わりにそれを使用してください。たとえば、行を'
で分割し、その中の単語の総数を出力する場合は、次のようにします。
val sink: Sink[String] = Sink.foreach(x => println(x.split(",").size))
FileIO.fromPath(Paths.get("a.csv"))
.via(Framing.delimiter(ByteString("\n"), 256, true).map(_.utf8String))
.to(sink)
.run()
Akka StreamsでCSVファイルを読み取る慣用的な方法は、 Alpakka CSVコネクタ を使用することです。次の例では、CSVファイルを読み取り、それを列名(ファイルの最初の行と想定)とByteString
値のマップに変換し、ByteString
値をString
値、および各行を出力します。
FileIO.fromPath(Paths.get("a.csv"))
.via(CsvParsing.lineScanner())
.via(CsvToMap.toMap())
.map(_.mapValues(_.utf8String))
.runForeach(println)
これを試して:
package ru.io
import Java.nio.file.Paths
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl._
import akka.util.ByteString
import scala.concurrent.Await
import scala.concurrent.duration._
object ReadStreamApp extends App {
implicit val actorSystem = ActorSystem()
import actorSystem.dispatcher
implicit val flowMaterializer = ActorMaterializer()
// читать строки из файла журнала
val logFile = Paths.get("src/main/resources/a.csv")
val source = FileIO.fromPath(logFile)
// анализировать фрагменты байтов в строки
val flow = Framing
.delimiter(ByteString(System.lineSeparator()), maximumFrameLength = 512, allowTruncation = true)
.map(_.utf8String)
val sink = Sink.foreach(println)
source
.via(flow)
.runWith(sink)
.andThen {
case _ =>
actorSystem.terminate()
Await.ready(actorSystem.whenTerminated, 1 minute)
}
}
ええ、これらは異なるSource
sなので問題ありません。しかし、あなたが気に入らない場合はscala.io.Source
自分でファイルを読み取って(ソースcsv
ファイルを圧縮する必要がある場合もあります)、次のように指定されたInputStream
を使用して解析できます
StreamConverters.fromInputStream(() => input)
.via(Framing.delimiter(ByteString("\n"), 4096))
.map(_.utf8String)
.collect { line =>
line
}
とは言っても、Apache Commons CSV
akka-streamを使用。あなたはより少ないコードを書くことになるかもしれません:)