我正在尝试使用Akka HTTP在我的应用程序中实现文件上载功能。我使用的是akka-stream
版本2.4.4
。
以下是代码(从akka-doc修改)
path("fileupload") {
post {
extractRequestContext {
ctx => {
implicit val materializer = ctx.materializer
implicit val ec = ctx.executionContext
fileUpload("fileUpload") {
case (metadata, byteSource) =>
val location = FileUtil.getUploadPath(metadata)
val updatedFileName = metadata.fileName.replaceAll(" ", "").replaceAll("\"", "")
val uniqFileName = uniqueFileId.concat(updatedFileName)
val fullPath = location + File.separator + uniqFileName
val writer = new FileOutputStream(fullPath)
val bufferedWriter = new BufferedOutputStream(writer)
val result = byteSource.map(s => {
bufferedWriter.write(s.toArray)
}).runWith(Sink.ignore)
val result1 = byteSource.runWith(Sink.foreach(s=>bufferedWriter.write(s.toArray)))
Await.result(result1, 5.seconds)
bufferedWriter.flush()
bufferedWriter.close()
complete(uniqFileName)
/*onSuccess(result) { x =>
bufferedWriter.flush()
bufferedWriter.close()
complete("hello world")
}*/
}
}
}
}
}
此代码工作正常,并将文件上传到给定路径。我通过附加UUID来生成新的文件名,以确保文件名是唯一的。所以我需要将新文件名返回给调用者。但是,此方法始终不返回文件名。有时,它以Response has no content
结束。
有谁能让我知道我在这里做错了什么?
答案 0 :(得分:17)
当您为此目的使用反应流时,无需使用标准阻塞流:
path("fileUpload") {
post {
fileUpload("fileUpload") {
case (fileInfo, fileStream) =>
val sink = FileIO.toPath(Paths.get("/tmp") resolve fileInfo.fileName)
val writeResult = fileStream.runWith(sink)
onSuccess(writeResult) { result =>
result.status match {
case Success(_) => complete(s"Successfully written ${result.count} bytes")
case Failure(e) => throw e
}
}
}
}
}
此代码会将fileUpload
多部分字段上传到/tmp
目录中的文件。它只是将输入源的内容转储到相应的文件接收器,在写操作完成后返回一条消息。
您可能还想调整用于FileIO
来源和接收器的调度程序,如their scaladocs中所述。
答案 1 :(得分:1)
如果您只需上传文件但在上传文件流完成之前没有做任何事情,那么有更简单的方法:
def tempDestination(fileInfo: FileInfo): File =
File.createTempFile(fileInfo.fileName, ".tmp")
val route =
storeUploadedFile("csv", tempDestination) {
case (metadata, file) =>
// do something with the file and file metadata ...
file.delete()
complete(StatusCodes.OK)
}