我的Scala应用程序启动了将文件写入磁盘的外部进程。在一个单独的线程中,我想读取该文件并将其内容复制到OutputStream
,直到该过程完成并且文件不再增长。
需要考虑几个边缘情况:
BTW我可以传递一个processCompletionFuture
变量的线程,该变量指示文件何时完成增长。
有一种优雅而有效的方法吗?也许使用Akka Streams或者演员?(我尝试过使用FileInputStream
的Akka Stream,但是一旦输入流中没有更多的字节,流似乎就会终止如果是#2)。
答案 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
。