在Scala中修改大文件

And*_*ner 6 file-io iterator scala postscript scala-2.9

我试图修改Scala中的大型PostScript文件(有些大小只有1GB).该文件是一组批次,每批包含代表批号,页数等的代码.

我需要:

  1. 在文件中搜索批处理代码(始终以文件中的同一行开头)
  2. 计算下一批代码之前的页数
  3. 修改批次代码以包括每批中的页数.
  4. 将新文件保存在其他位置.

我当前的解决方案使用两个迭代器(iterAiterB),从中创建Source.fromFile("file.ps").getLines.第一个迭代器(iterA)遍历一个while循环到批处理代码的开头(iterB.next每次都被调用).iterB然后继续搜索,直到下一个批处理代码(或文件末尾),计算它经过的页面数量.然后,它更新批次代码iterA的位置,重复该过程.

这似乎非Scala-like,我仍然没有设计好将这些更改保存到新文件的方法.

解决这个问题的好方法是什么?我应该完全抛弃迭代器吗?我最好喜欢这样做而不必将整个输入或输出同时存入内存.

谢谢!

ste*_*ins 3

您或许可以使用 Scala 的Stream类来实现这一点。我假设您不介意一次在内存中保存一个“批次”。

import scala.annotation.tailrec
import scala.io._

def isBatchLine(line:String):Boolean = ...

def batchLine(size: Int):String = ...

val it = Source.fromFile("in.ps").getLines
// cannot use it.toStream here because of SI-4835
def inLines = Stream.continually(i).takeWhile(_.hasNext).map(_.next)

// Note: using `def` instead of `val` here means we don't hold
// the entire stream in memory
def batchedLinesFrom(stream: Stream[String]):Stream[String] = {
  val (batch, remainder) = stream span { !isBatchLine(_) }
  if (batch.isEmpty && remainder.isEmpty) { 
    Stream.empty
  } else {
    batchLine(batch.size) #:: batch #::: batchedLinesFrom(remainder.drop(1))
  }
}

def newLines = batchedLinesFrom(inLines dropWhile isBatchLine)

val ps = new java.io.PrintStream(new java.io.File("out.ps"))

newLines foreach ps.println

ps.close()
Run Code Online (Sandbox Code Playgroud)