Java 在functional scala中读取大文件

Java 在functional scala中读取大文件,java,scala,file-io,Java,Scala,File Io,我正试图用scala处理一个大的二进制文件。如果可能的话,我想使用功能性方法。我现在的主要方法如下所示: def getFromBis( buffer:List[Byte], bis:BufferedInputStream ):(Byte,List[Byte],Boolean) = { buffer match { case Nil => val buffer2 = new Array[Byte](100000) bi

我正试图用scala处理一个大的二进制文件。如果可能的话,我想使用功能性方法。我现在的主要方法如下所示:

def getFromBis( buffer:List[Byte], bis:BufferedInputStream ):(Byte,List[Byte],Boolean) = {
    buffer match {
        case Nil =>
            val buffer2 = new Array[Byte](100000)
            bis.read(buffer2) match {
                case -1 => (-1,Nil,false)
                case _  => 
                    val buffer3 = buffer2.toList
                    (buffer3.head,buffer3.tail,true)
            }
        case b::tail => return (b,tail,true)
    }
}
它接受一个列表缓冲区和一个缓冲的输入流。如果缓冲区不是空的,它只返回head和tail,如果是空的,它从文件中获取下一个块,并将其用作缓冲区

正如你所见,这不是很实用。我正试图以一种尽可能少的底层io调用的方式来实现这一点,这就是为什么我要以分块的方式来实现这一点。这里的问题是新数组。每次我运行函数时,它都会创建一个新的数组,从程序运行时不断增加的内存使用情况来看,我认为它们不会被破坏


我的问题是:有没有更好的方法使用scala以分块方式读取大文件?我想保留一个完全功能化的方法,但至少我需要一个可以作为我的其他功能程序的黑盒的函数。

您几乎肯定不想在
列表中存储字节。每个字节都需要一个新对象。这是非常低效的,并且可能会导致比您需要的内存使用量多20倍

最简单的方法是创建一个迭代器来存储内部状态:

class BisReader(bis: BufferedInputStream) {
  val buffer = new Array[Byte](100000)
  var n = 0
  var i = 0
  def hasNext: Boolean = (i < n) || (n >= 0 && {
    n = bis.read(buffer)
    i = 0
    hasNext
  })
  def next: Byte = {
    if (i < n) {
      val b = buffer(i)
      i += 1
      b
    }
    else if (hasNext) next
    else throw new IOException("Input stream empty")
  }
}
implicit def reader_as_iterator(br: BisReader) = new Iterator[Byte] {
  def hasNext = br.hasNext
  def next = br.next
}
类BisReader(bis:BufferedInputStream){
val buffer=新数组[字节](100000)
var n=0
变量i=0
def hasNext:Boolean=(i=0&&{
n=双读(缓冲区)
i=0
哈斯奈特
})
def next:字节={
if(i
可以让BisReader扩展迭代器[Byte],但由于迭代器不是专用的,这将需要对原始next/hasNext访问进行装箱。通过这种方式,您可以在需要时以全速获得低级(next/hasNext)访问,否则可以使用方便的迭代器方法

现在,您已经用一个干净的接口将丑陋的非功能性Java IO内容隔离在一个类中,并且可以恢复到功能性



编辑:当然,除了IO依赖于顺序并且有副作用外,前面的方法也不能解决这一问题。

关于以事件流式样式处理大文件可以帮助您。它很老了,但我觉得还是不错。你真棒,谢谢!到目前为止,我一直在做的就是发送字节列表,在这里和那里去掉头,但我想我可以发送一个索引变量。@Mediocre Gopher-只需发送一个
BisReader
的实例,并在需要时用
next
抓取一个项目。如果您想要最大的效率,您也可以创建自己的等价物
getOrElse
,这样您就不必一直担心检查
hasNext
。您不是还在装箱每个字节,还是迭代器得到了专门化处理?@oxbow\u lakes-如果您使用
迭代器[Byte]
它被装箱了。如果使用
BisReader
,它看起来就像迭代器,但使用的是原语。如果需要,隐式包装器将返回到装箱,但至少您有一个高性能的
hasNext
next
@Rex-您是对的;当我读到答案中的“迭代器”时,我假设您的
BisReader
实现了
Iterator