使用scala中的akka流读取多个文件

使用scala中的akka流读取多个文件,scala,akka,akka-stream,Scala,Akka,Akka Stream,我正在尝试用akka流读取多个文件,并将结果放入列表中。 我可以毫无问题地读取一个文件。返回类型为Future[Seq[String]]。问题是在未来处理序列必须进入onComplete{}中 我正在尝试下面的代码,但显然它不会工作。onComplete之外的列表acc为空。但在不完整的内部保存值。我理解这个问题,但我不知道如何解决这个问题 // works fine def readStream(path: String, date: String): Future[Seq[String]

我正在尝试用akka流读取多个文件,并将结果放入列表中。 我可以毫无问题地读取一个文件。返回类型为Future[Seq[String]]。问题是在未来处理序列必须进入onComplete{}中

我正在尝试下面的代码,但显然它不会工作。onComplete之外的列表acc为空。但在不完整的内部保存值。我理解这个问题,但我不知道如何解决这个问题

// 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}
//很好用
def readStream(路径:字符串,日期:字符串):未来[Seq[String]={
隐式val系统=ActorSystem(“Sys”)
val设置=ActormatarializerSettings(系统)
隐式val-materializer=actormatarializer(设置)
val结果:未来[序列[字符串]]=
FileIO.fromPath(path.get(path+“transactions”+date+
“.data”))
.via(Framing.delimiter(ByteString(“\n”),256,true))
.map(u.utf8String)
.toMat(水槽顺序)(保持右侧)
.run()
var aa:List[scala.Array[String]=Nil
结果.onComplete(x=>{
aa=x.get.map(line=>line.split(“|”).toList
})
后果
}
//这行不通
def concatFiles(路径:String,日期:String,numberOfDays:Int):
列表[scala.Array[String]={
val formatter=模式的DateTimeFormatter.of(“yyyyMMdd”);
val formattedDate=LocalDate.parse(日期,格式化程序);
var acc=List[scala.Array[String]]()
为了{
结果=x.get.map(line=>line.split(“|”).toList
acc=acc++结果})
}
acc}

通用解决方案

给定
路径
值的迭代器,可以通过组合&>来创建文件行的

问题申请

列表
为空的原因是
未来
值尚未完成,因此在函数返回列表之前,您的可变列表不会更新

对问题代码的评论

问题中代码的组织和风格表明了与
akka
Future
相关的一些误解。我认为您正在尝试一个相当复杂的工作流,而不了解您尝试使用的工具的基本原理

1.不应在每次调用函数时创建
ActorSystem
。每个应用程序通常有一个ActorSystem,并且只创建一次

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

def readStream(...
2.应尽量避免可变集合,而是使用具有相应功能的
迭代器

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]]

停留在akka内:可能重复
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)