使用akka流下载指定的文件?

时间:2018-02-02 08:02:39

标签: scala akka akka-stream

对于以下代码,我需要客户端将文件名发送到服务器,然后服务器可以回复客户端指定文件的内容。如果我没有指定文件名,只是在服务器部分硬编码,但客户端如何告诉服务器需要指定文件,它可以工作吗?

Server.scala

package com.tst

import java.nio.file.Paths
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Tcp.{IncomingConnection, ServerBinding}
import akka.stream.scaladsl._
import akka.util.ByteString
import scala.concurrent.Future

object Server extends App {
  implicit val system = ActorSystem()
  implicit val ec = system.dispatcher
  implicit val materializer = ActorMaterializer()

  val connections: Source[IncomingConnection, Future[ServerBinding]] =
    Tcp().bind("127.0.0.1", 9989)
  connections runForeach { connection =>
    println(s"New connection from: ${connection.remoteAddress}")
    var fileName = ""

    // NOTE: here, the fileName = item can not affect the latter runWith,
    // I want to find solution
    val go = Flow[ByteString].via(connection.flow).map(_.utf8String).map {
      item => println(item); fileName = item
    }.runWith(FileIO.fromPath(Paths.get(fileName)), Sink.ignore)
  }
}

Client.scala

package com.tst

import java.nio.file.Paths
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl._
import akka.util.ByteString

object Client extends App {
  implicit val system = ActorSystem()
  implicit val ec = system.dispatcher
  implicit val materializer = ActorMaterializer()

  val connection = Tcp().outgoingConnection("127.0.0.1", 9989)
  val f = Source(List("D:/testinput.txt")).map(ByteString(_)).via(connection).
    runWith(FileIO.toPath(Paths.get("D:/testoutput.txt")))
  f.foreach {
    _ =>
      println("done")
      system.terminate()
  }
}

build.sbt

name := "streamtest"

version := "1.0"

scalaVersion := "2.11.8"

libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-stream" % "2.4.20"
)

1 个答案:

答案 0 :(得分:2)

在服务器端,您可以使用Connection Flow方法与import akka.stream.scaladsl.FileIO import java.nio.file.Paths val fileNameToContentsFlow : Flow[ByteString, ByteString, _] = Flow[ByteString] .map(_.utf8String) .take(1L) .map(fileName => Paths.get(fileName)) .flatMapConcat( filePath => FileIO.fromPath(filePath) ) 结合使用文件名并生成文件行:

.take(1L)

注意:我添加了connections runForeach { connection => connection.handleWith(fileNameToContentsFlow) } ,以便客户端每个连接只能访问1个文件。这可以修改为每个连接处理多个文件,但是需要在每个单独文件的内容之间插入适当的分隔符。

然后会稍微修改您的服务器代码

{{1}}