Scala流式传输实时/增长文件

时间:2018-04-21 23:32:38

标签: scala akka streaming akka-stream akka-actor

我的Scala应用程序启动了将文件写入磁盘的外部进程。在一个单独的线程中,我想读取该文件并将其内容复制到OutputStream,直到该过程完成并且文件不再增长。

需要考虑几个边缘情况:

  1. 当线程准备好开始时,该文件可能还不存在。
  2. 线程可以比进程写入更快地复制。换句话说,当文件仍在增长时,它可能会到达文件的末尾。
  3. BTW我可以传递一个processCompletionFuture变量的线程,该变量指示文件何时完成增长。

    有一种优雅而有效的方法吗?也许使用Akka Streams或者演员?(我尝试过使用FileInputStream的Akka Stream,但是一旦输入流中没有更多的字节,流似乎就会终止如果是#2)。

1 个答案:

答案 0 :(得分:2)

Alpakka是一个基于Akka Streams构建的库,它有一个模仿import akka.NotUsed import akka.stream._ import akka.stream.scaladsl._ import akka.stream.alpakka.file.scaladsl._ import akka.util.{ ByteString, Timeout } import java.io.OutputStream import java.nio.file.Path import scala.concurrent._ import scala.concurrent.duration._ val path: Path = ??? val maxLineSize = 10000 val tailSource: Source[ByteString, NotUsed] = FileTailSource( path = path, maxChunkSize = maxLineSize, startingPosition = 0, pollingInterval = 500.millis ).via(Framing.delimiter(ByteString(System.lineSeparator), maxLineSize, true)) Unix命令的FileTailSource实用程序。例如:

tailSource

上面的OutputStream逐行读取整个文件,并且每500毫秒不断读取新添加的数据。要将流内容复制到val stream: Future[IOResult] = tailSource .runWith(StreamConverters.fromOutputStream(() => new OutputStream { override def write(i: Int): Unit = ??? override def write(bytes: Array[Byte]): Unit = ??? })) ,请将源连接到StreamConverters.fromOutputStream接收器:

FileTailSource.lines

(请注意,有Source[String, NotUsed]方法可生成ByteString,但在这种情况下使用String代替FileTailSource.apply()更为合适这就是为什么该示例使用Source[ByteString, NotUsed]生成{{1}}。)

的原因

如果文件在实现时不存在,则流将失败。因此,在运行流之前,您需要确认文件是否存在。这可能有点矫枉过正,但有一个想法是使用Alpakka的DirectoryChangesSource