java.nio.ByteBuffer wrap 方法部分与 sbt 一起使用 运行

java.nio.ByteBuffer wrap method partly working with sbt run

我有一个问题,我从一个大文件 ~ (100MB) 中读取了一个字节流,并且在一些整数之后我得到了值 0(但仅限于 sbt 运行 )。当我点击 IntelliJ 上的播放按钮时,我得到了我期望的 > 0 的值。

我的猜测是环境有所不同。但是我看不出有什么不同。

// DemoApp.scala
import java.nio.{ByteBuffer, ByteOrder}

object DemoApp extends App {
  val inputStream = getClass.getResourceAsStream("/HandRanks.dat")
  val handRanks = new Array[Byte](inputStream.available)
  inputStream.read(handRanks)
  inputStream.close()

  def evalCard(value: Int) = {
    val offset = value * 4
    println("value: " + value)
    println("offset: " + offset)
    ByteBuffer.wrap(handRanks, offset, handRanks.length - offset).order(ByteOrder.LITTLE_ENDIAN).getInt
  }

  val cards: List[Int] = List(51, 45, 14, 2, 12, 28, 46)

  def eval(cards: List[Int]): Unit = {
    var p = 53
    cards.foreach(card =>  {
      println("p = " + evalCard(p))
      p = evalCard(p + card)
    })
    println("result p: " + p);
  }
  eval(cards)
}

HandRanks.dat可以在这里找到:(我把它放在一个名为资源的目录中) https://github.com/Robert-Nickel/scala-texas-holdem/blob/master/src/main/resources/HandRanks.dat

build.sbt 是:

name := "LoadInts"
version := "0.1"
scalaVersion := "2.13.4"

在我的 windows 机器上,我使用 sbt 1.4.6 和 Oracle Java 11

您会看到 evalCard 调用将工作 4 次,但在第五次之后 return 值为 0。它应该大于 0,这是在使用 IntelliJ 的播放按钮时.

您没有阅读全部内容。这个

val handRanks = new Array[Byte](inputStream.available)

仅分配 InputStream 缓冲区,然后您使用

读取缓冲区中的数量
inputStream.read(handRanks)

根据默认设置,您将处理不同数量的数据,但它们永远不会是 100MB 的数据。为此,您必须将数据读入循环中的某个结构(坏主意)或分块处理(使用迭代器、流等)。

import scala.util.Using

// Using will close the resource whether error happens or not
Using(getClass.getResourceAsStream("/HandRanks.dat")) { inputStream =>
  def readChunk(): Option[Array[Byte]] = {
    // can be done better, but that's not the point here
    val buffer = new Array[Byte](inputStream.available)
    val bytesRead = inputStream.read(buffer)
    if (bytesRead >= 0) Some(buffer.take(bytesRead))
    else None
  }
  
  @tailrec def process(): Unit = {
    readChunk() match {
      case Some(chunk) =>
        // do something
        process()
      case None =>
        // nothing to do - EOF reached
    }
  }

  process()
}