Akka Streams文件处理和终止

时间:2018-01-26 11:21:50

标签: scala akka-stream

我有以下代码片段,它会读取一个CSV文件并只是向控制台输出内容:

def readUsingAkkaStreams = {

    import java.io.File
    import akka.stream.scaladsl._
    import akka.actor.ActorSystem
    import akka.stream.ActorMaterializer
    import java.security.MessageDigest


    implicit val system = ActorSystem("Sys")
    implicit val materializer = ActorMaterializer()

    val file = new File("/path/to/csv/file.csv")

    val fileSource = FileIO.fromFile(file, 65536)

    val flow = fileSource.map(chunk => chunk.utf8String)

    flow.to(Sink.foreach(println(_))).run
  }

我现在对此有一些疑问:

  1. chunksize是以字节为单位的大小。它是如何在内部处理的?我的意思是,我最终会遇到一个块可能只包含一行中的部分元素的情况吗?

  2. 此流如何终止?现在它没有!我希望它知道它已完全读取文件并应触发停止信号!有机制这样做吗?

  3. 编辑1:根据以下帖子的建议,我收到错误消息,如屏幕截图所示!

    enter image description here

    编辑2:

    通过设置maximumFrameLength以匹配最大块大小(65536)的大小来管理以消除错误。

    val file = new File("/path/to/csf/file.csv")
    val chunkSize = 65536
    val fileSource = FileIO.fromFile(file, chunkSize).via(Framing.delimiter(
      ByteString("\n"),
      maximumFrameLength = chunkSize,
      allowTruncation = true))
    

1 个答案:

答案 0 :(得分:1)

1.根据docs

发出的元素是chunkSize大小的ByteString元素,但最终元素除外,它的大小最多为chunkSize。

FileIO来源将新行视为任何其他字符。所以是的,你可能会在一个块中看到CSV行的第一部分,而在另一个块中看到第二部分。如果这不是您想要的,您可以使用ByteString重新构建Framing.delimiter流的分块方式(有关详情,请参阅docs)。

作为旁注,FileIO.fromFile已被弃用,请更好地使用FileIO.fromPath

一个例子是:

val fileSource = FileIO.fromPath(...)
  .via(Framing.delimiter(
    ByteString("\n"),
    maximumFrameLength = 256,
    allowTruncation = true))

2.接收器实现为Future,您可以映射到流终止时执行某些操作:

val result: Future[IOResult] = flow.runWith(Sink.foreach(println(_)))

result.onComplete(...)