我正在尝试使用akka流读取多个文件,并将结果放入列表中。 我可以毫无问题地读取一个文件。返回类型为Future [Seq [String]]。问题是处理Future内部的序列必须放在onComplete {}内部。
我正在尝试以下代码,但显然无法正常工作。 onComplete之外的列表acc为空。但将值保存在inComplete中。我了解这个问题,但我不知道该如何解决。
// works fine
def readStream(path: String, date: String): Future[Seq[String]] = {
implicit val system = ActorSystem("Sys")
val settings = ActorMaterializerSettings(system)
implicit val materializer = ActorMaterializer(settings)
val result: Future[Seq[String]] =
FileIO.fromPath(Paths.get(path + "transactions_" + date +
".data"))
.via(Framing.delimiter(ByteString("\n"), 256, true))
.map(_.utf8String)
.toMat(Sink.seq)(Keep.right)
.run()
var aa: List[scala.Array[String]] = Nil
result.onComplete(x => {
aa = x.get.map(line => line.split('|')).toList
})
result
}
//this won't work
def concatFiles(path : String, date : String, numberOfDays : Int) :
List[scala.Array[String]] = {
val formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
val formattedDate = LocalDate.parse(date, formatter);
var acc = List[scala.Array[String]]()
for( a <- 0 to numberOfDays){
val date = formattedDate.minusDays(a).toString().replace("-", "")
val transactions = readStream(path , date)
var result: List[scala.Array[String]] = Nil
transactions.onComplete(x => {
result = x.get.map(line => line.split('|')).toList
acc= acc ++ result })
}
acc}
答案 0 :(得分:1)
常规解决方案
鉴于Paths
值的迭代器,可以通过组合FileIO
和flatMapConcat
来创建文件行的Source
:
val lineSourceFromPaths : (() => Iterator[Path]) => Source[String, _] = pathsIterator =>
Source
.fromIterator(pathsIterator)
.flatMapConcat { path =>
FileIO
.fromPath(path)
.via(Framing.delimiter(ByteString("\n"), 256, true))
.map(_.utf8String)
}
问题申请
您的List
为空的原因是因为Future
的值尚未完成,因此可变的列表在函数返回列表之前不会被更新。
有关代码的评论
问题中代码的组织和样式表明与akka
和Future
有关的一些误解。我认为您正在尝试一个相当复杂的工作流程,而没有了解要使用的工具的基本原理。
1。不应在每次调用函数时创建一个ActorSystem
。通常每个应用程序有1个ActorSystem,并且仅创建一次。
implicit val system = ActorSystem("Sys")
val settings = ActorMaterializerSettings(system)
implicit val materializer = ActorMaterializer(settings)
def readStream(...
2。您应避免使用可变的集合,而应使用具有相应功能的Iterator
:
def concatFiles(path : String, date : String, numberOfDays : Int) : List[scala.Array[String]] = {
val formattedDate = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyyMMdd"))
val pathsIterator : () => Iterator[Path] = () =>
Iterator
.range(0, numberOfDays+1)
.map(formattedDate.minusDays)
.map(_.String().replace("-", "")
.map(path => Paths.get(path + "transactions_" + date + ".data")
lineSourceFromPaths(pathsIterator)
3。由于您正在与期货交易,因此您不应该等待期货交易完成,而应该将concateFiles
的退货类型更改为Future[List[Array[String]]]
。