Scala:逐行读取巨大的压缩文本文件而不加载到内存中

问题描述 投票:0回答:3

我有一个大小为 100-200 GB 的文本文件。所以我希望以压缩格式存储(例如zip)。但是,由于其大小,我需要一次处理一行。虽然使用

io.Source.fromFile(fileName).getLines
一次一行读取文本文件很简单,但这仅适用于解压缩的文件。

有没有一些有效的方法可以在scala中逐行读取压缩文件?我找不到任何示例,但我看到的更接近的实现是here,但它将文件加载到内存中。与通常给出的使用 zip 存档的示例不同,我只需要处理一个压缩的文本文件。如果有任何指示或线索,我将不胜感激。

scala io compression
3个回答
5
投票

如果文件是 Gzipped,java 的

GzipInputStream
为您提供流式访问:

   val lines: Iterator[String] = Source
     .fromInputStream(new GzipInputStream(new FileInputStream("foo.gz")))
     .getLines

如果它是一个 zip 存档,正如您的问题所示,那就更复杂了。 Zip 存档更像是文件夹而不是单个文件。您必须先阅读目录,然后浏览条目以找到您想要阅读的条目(或阅读所有条目)。类似于这个


3
投票

考虑better-files,它会在压缩文件中提供

Iterator

import better.files._
File("foo.gz").newInputStream.asGzipInputStream().lines
// : Iterator[String]

这样您就可以逐行处理文件,而无需将其整个加载到内存中。


0
投票

提供 zip 中所有文件中所有行的 LazyList。 (标量 3)

import java.io.{ FileInputStream, BufferedReader, InputStreamReader }
import java.util.zip.{ ZipEntry, ZipInputStream }
import scala.jdk.CollectionConverters.*

// lazily read all lines from all entries in zip file
def readZipRows(fname: String): LazyList[String] = {
  val zipStream: ZipInputStream = new ZipInputStream(new FileInputStream(fname))

  val entryStream: LazyList[ZipEntry] = LazyList.continually(zipStream.getNextEntry).takeWhile(_ != null)
  val lines: LazyList[String] = entryStream.flatMap { (zipEntry: ZipEntry) =>
    val br = new BufferedReader(new InputStreamReader(zipStream))
    for {
      row <- br.lines.iterator.asScala
    } yield row
  }
  lines
}
© www.soinside.com 2019 - 2024. All rights reserved.