2017-08-03 1 views
1

La directive Akka "fileUpload" copie-t-elle en mémoire le fichier entier de l'entité en entrée? Existe-t-il un moyen de télécharger en plusieurs parties un gros fichier de 1 Go sans consommer 1 Go de mémoire?Akka directive fileUpload copie le fichier entier de l'entité en entrée dans la mémoire?

approche
 val uploadFile = File.createTempFile("uploadFile", ".txt") 
     extractRequestContext { ctx => 
     implicit val materializer = ctx.materializer 
     implicit val ec = ctx.executionContext 

     fileUpload("csv") { 
      case (metadata, byteSource) => 
      val sumF = byteSource.runFold(ByteString.empty) { case (acc, i) => acC++ i }.map(s => s.utf8String) 

      onSuccess(sumF) { sum => 
       Files.write(Paths.get(uploadFile.getAbsolutePath), sum.toString.getBytes) 
       logger.info(StatusCodes.OK + "Successfully completed fileUpload ") 
       complete(s"Successfully completed fileUpload") }} 
     } 

Répondre

0

Votre courant rassemble tout le fichier en mémoire. Pour éviter de faire cela, le flux fichier sur le disque avec un sink:

val uploadFile = File.createTempFile("uploadFile", ".txt") 

extractRequestContext { ctx => 
    implicit val materializer = ctx.materializer 
    implicit val ec = ctx.executionContext 

    fileUpload("csv") { 
    case (metadata, byteSource) => 
     val result = 
     byteSource.via(Framing.delimiter(ByteString("\n"), 10000)) 
        .runWith(FileIO.toPath(Paths.get(uploadFile.getAbsolutePath))) 

     onSuccess(result) { res => 
     logger.info(StatusCodes.OK + "Successfully completed fileUpload ") 
     complete(s"Successfully completed fileUpload") 
     } 
    } 
} 

Vous pourriez avoir besoin d'ajuster akka.http.server.parsing.max-content-length ou maximumFrameLength dans le séparateur (10000 dans l'exemple ci-dessus).

0

Merci, le problème était avec runFold, avec runWith résolu le problème.

 extractDataBytes { bytes => 

        val path = Files.createTempFile(ATTACHMENT_NAME + "_" + "upload", "dat") 

        val futureWriteResult: Future[IOResult] = bytes.runWith(FileIO.toPath(path)) 


        onSuccess(futureWriteResult) { 
        case IOResult(count, Success(Done)) => UploadContent(path, parent, tenant, ATTACHMENT_NAME, async).execute() 
        case IOResult(_, Failure(ex)) => throw ex 
        } 
       }