Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
File Ktor-处理大文件操作而不发生内存泄漏_File_Kotlin_Memory Leaks_Backend_Ktor - Fatal编程技术网

File Ktor-处理大文件操作而不发生内存泄漏

File Ktor-处理大文件操作而不发生内存泄漏,file,kotlin,memory-leaks,backend,ktor,File,Kotlin,Memory Leaks,Backend,Ktor,我对后端开发非常陌生。基本上,我想创建一个健壮而简单的应用程序,它将在params中接受zip文件URL,然后从URL下载zip文件,最后提取zip并返回其中的bin文件。注意:zip文件大小的范围从5MB到150MB。我已尝试按以下方式执行所述操作 package la.sample import io.ktor.application.Application import io.ktor.application.call import io.ktor.client.HttpClient i

我对后端开发非常陌生。基本上,我想创建一个健壮而简单的应用程序,它将在params中接受zip文件URL,然后从URL下载zip文件,最后提取zip并返回其中的
bin
文件。注意:zip文件大小的范围从5MB到150MB。我已尝试按以下方式执行所述操作

package la.sample

import io.ktor.application.Application
import io.ktor.application.call
import io.ktor.client.HttpClient
import io.ktor.client.request.get
import io.ktor.http.HttpStatusCode
import io.ktor.response.respond
import io.ktor.response.respondFile
import io.ktor.routing.get
import io.ktor.routing.routing
import java.io.*


fun Application.startServer() {
    routing {
        get("/get-bin") {

            //Gets the AWS Url from params
            val awsUrl = call.request.queryParameters.get("url") ?: "Error"

            // Download the zip file from the AWS URL
            val client = HttpClient()
            val bytes = client.get<ByteArray>(awsUrl)

            //Create a temp file on the server & write the zip file bytes into it.
            val file = File(".", "data.zip") 
            file.writeBytes(bytes) 
            
            //Call a method to unzip the file
            unzipAndReturnBinFile()?.let { 
                call.respondFile(it) //respond with bin file
            } ?: kotlin.run{
                call.respond(HttpStatusCode.InternalServerError)
            }
        }
    }
}


fun unzipAndReturnBinFile(): File? {

    var exitVal = 0

    //Command shell to unzip the file
    Runtime.getRuntime().exec("unzip bundle.zip -d data").let {//command shell to unzip the zip file
        exitVal += it.waitFor()
    }

    //Check if the command executed successfully 
    if (exitVal == 0) {

        var binFile: File? = null

        //check if the extracted files contain `bin`
        File("data").listFiles().forEach {

        if (it.name.contains(".bin")) {
            binFile = it
        }
    }

    //return bin or null otherwise
    return binFile
} else {
    throw Exception("Command Shell Execution failed.")
}
}
包la.sample
导入io.ktor.application.application
导入io.ktor.application.call
导入io.ktor.client.HttpClient
导入io.ktor.client.request.get
导入io.ktor.http.HttpStatusCode
导入io.ktor.response.response
导入io.ktor.RESPOND.respondFile
导入io.ktor.routing.get
导入io.ktor.routing.routing
导入java.io*
有趣的应用程序{
路由{
get(“/get bin”){
//从参数获取AWS Url
val awsUrl=call.request.queryParameters.get(“url”)?:“错误”
//从AWS URL下载zip文件
val client=HttpClient()
val bytes=client.get(awsUrl)
//在服务器上创建一个临时文件并将zip文件字节写入其中。
val文件=文件(“.”,“data.zip”)
file.writeBytes(字节)
//调用一个方法来解压缩文件
unzipAndReturnBinFile()?.let{
call.respondFile(it)//用bin文件响应
}?:kotlin.run{
call.respond(HttpStatusCode.InternalServerError)
}
}
}
}
fun unzipAndReturnBinFile():文件?{
var exitVal=0
//命令shell解压文件
Runtime.getRuntime().exec(“unzip bundle.zip-d data”)。让{//命令shell解压缩zip文件
exitVal+=it.waitFor()
}
//检查命令是否成功执行
如果(exitVal==0){
var binFile:文件?=null
//检查提取的文件是否包含“bin”`
文件(“数据”).listFiles().forEach{
if(it.name.contains(“.bin”)){
binFile=it
}
}
//返回bin或null,否则为空
返回二进制文件
}否则{
抛出异常(“命令外壳程序执行失败”)
}
}
无论Zip文件大小如何,上述代码在本地计算机中都可以正常工作。但是当它部署到AWS时,如果zip或bin文件大于100 MB,代码就会中断,并给出
java.lang.OutOfMemoryError
错误。如果有人能向我建议一种在后端处理大文件操作的正确方法,并且能够处理100次这样的并发调用,我将非常感激。多谢各位

我的远程机器的Java堆大小约为1GB。

您的问题不在于解压缩过程

运行时
exec
命令在不同的进程上运行,并且只在分叉进程的堆上使用最小大小来保存返回地址的指令

导致outOfMemory的问题在以下几行中

val bytes = client.get<ByteArray>(awsUrl)
val file = File(".", "data.zip") 
file.writeBytes(bytes) 
或者,如果您希望对程序进行更多控制,请尝试使用Ben Noland回答


根据@Naor的评论,我已经更新了代码,以接受多部分文件,并在获得它们后立即将每个小卡盘(部件)写入另一个文件,而不将整个数据存储在内存中。它解决了这个问题。下面是更新的代码片段

        val file = File(".", Constant.FILE_PATH)
        call.receiveMultipart().apply {
            forEachPart {
                if (it is PartData.FileItem) {
                    it.streamProvider().use { input ->
                        file.outputStream().buffered().use { output -> input.copyToSuspend(output) }
                    }
                }
                it.dispose
            } }

OutOfMemoryError
不仅仅发生在内存泄漏的情况下,它可能真正意味着机器或jvm内存不足。JVM上有什么设置,机器有多少可用内存?@Alex.T为java程序分配了大约1GB的堆大小。exec命令应该在不同的进程上运行,除了进程之外,变量不应该在堆上使用任何内存?你能附加一个堆栈跟踪吗!正是他们造成了问题。根据您的回答,我更改了代码,以接收多部分文件,并在获得卡盘后立即将其写入另一个文件,而不是将其存储在内存中。它很有魅力。谢谢。
        val file = File(".", Constant.FILE_PATH)
        call.receiveMultipart().apply {
            forEachPart {
                if (it is PartData.FileItem) {
                    it.streamProvider().use { input ->
                        file.outputStream().buffered().use { output -> input.copyToSuspend(output) }
                    }
                }
                it.dispose
            } }