如何在内存中处理10GB+大Tar文件(Docker磁盘受限场景)
处理大体积Tar文件的流式解析问题
场景说明
用Kotlin构建接口,接收10GB以上的Tar文件并逐个处理其中的JSON内容。Tar包包含数百万个JSON文件,应用部署在磁盘空间极其有限的Docker容器中,无法将整个归档文件解压到临时目录。
初始尝试与报错
采用Apache Compress流式处理时,代码如下:
post(...) { val multipart = call.receiveMultipart() multipart.forEachPart { part -> if (part is PartData.FileItem) { part.streamProvider().use { inputStream -> BufferedInputStream(inputStream).use { bufferedInputStream -> TarArchiveInputStream(bufferedInputStream).use { tarInput -> // 处理逻辑 } } } } } }
运行时出现错误:java.io.IOException: Corrupted TAR archive.,原因是采用流式提供Tar数据而非全量加载到内存,但又无法将整个输入流读取到ByteArray变量中(内存不足以容纳20GB数据)。
相关类型说明:
- inputStream ->
java.io.InputStream - bufferedStream ->
java.io.BufferedInputStream
代码更新:直接接收请求体
将文件作为POST请求体发送的完整示例:
call.receiveStream().buffered().use { bufferedInputStream -> TarArchiveInputStream(bufferedInputStream).use { tarInput -> var entry = tarInput.nextEntry while (entry != null) { if (!entry.isDirectory && entry.name.endsWith(".json")) { scope.launch { val jsonString = tarInput.bufferedReader().readText() val json: Map<String, JsonElement> = Json.parseToJsonElement(jsonString).jsonObject // JSON处理逻辑 } entry = tarInput.nextEntry } } } }
问题解决后的最终实现
// 任何实现java.io.InputStream的流都可使用 val bodyStream = call.receiveStream() val elems = sequence { bodyStream.buffered().use { bufferedInputStream -> TarArchiveInputStream(bufferedInputStream).use { tarInput -> while (true) { val entry = tarInput.nextEntry ?: break // 处理当前entry,调用yield()返回处理结果,后续可批量/逐个处理 yield(/* 返回处理后的内容 */) } } } }
经确认,问题根源在于Tar文件的异步处理逻辑冲突,调整为序列(Sequence)同步流式处理后解决。
内容的提问来源于stack exchange,提问作者canersevdiceginibekleyenoglu
相关产品推荐
相关产品推荐

