我有一个大小为 100-200 GB 的文本文件。所以我希望以压缩格式存储(例如zip)。但是,由于其大小,我需要一次处理一行。虽然使用
io.Source.fromFile(fileName).getLines
一次一行读取文本文件很简单,但这仅适用于解压缩的文件。
有没有一些有效的方法可以在scala中逐行读取压缩文件?我找不到任何示例,但我看到的更接近的实现是here,但它将文件加载到内存中。与通常给出的使用 zip 存档的示例不同,我只需要处理一个压缩的文本文件。如果有任何指示或线索,我将不胜感激。
如果文件是 Gzipped,java 的
GzipInputStream
为您提供流式访问:
val lines: Iterator[String] = Source
.fromInputStream(new GzipInputStream(new FileInputStream("foo.gz")))
.getLines
如果它是一个 zip 存档,正如您的问题所示,那就更复杂了。 Zip 存档更像是文件夹而不是单个文件。您必须先阅读目录,然后浏览条目以找到您想要阅读的条目(或阅读所有条目)。类似于这个
考虑better-files,它会在压缩文件中提供
Iterator
import better.files._
File("foo.gz").newInputStream.asGzipInputStream().lines
// : Iterator[String]
这样您就可以逐行处理文件,而无需将其整个加载到内存中。
提供 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
}