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