You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala中BufferedReader读取Google Storage文件字符数不一致问题

解决Scala中BufferedReader读取Google Storage文件时缓冲区不满的问题

这其实是BufferedReader.read(char[])方法的正常行为,我来给你拆解下原因和对应的解决办法:

为什么会出现读取字符数小于缓冲区大小的情况?

BufferedReader.read(char[])的设计逻辑是尽可能多地将字符读入缓冲区,但不保证填满整个缓冲区。出现短读的场景通常有这些:

  • 文件剩余的字符数不足缓冲区的长度(比如文件末尾的最后一段)
  • 底层流(这里是Google Storage的输入流)本身是分块传输的,当到达分块边界时会提前返回已读取的字符

这不是代码bug,而是IO流API的标准行为。

解决方案:根据需求选择处理方式

需求1:只要正确读取所有内容,不强制固定块大小

如果你的目标只是完整读取文件内容,那原来的代码其实是没问题的——短读的部分只是流末尾或者分块边界的正常情况,你只需要继续处理返回的字符即可,不需要额外修改。

需求2:必须每次处理固定300字符的块(除了最后一块)

如果业务逻辑要求每次处理严格300字符的块,那需要手动实现循环填充缓冲区的逻辑,直到缓冲区填满或者流到达末尾。修改后的代码如下:

val path_gs = new Path("gs://bucket")
val filename= "filename.txt"
val fs = path_gs.getFileSystem(new Configuration())
val dataInputStream: FSDataInputStream = fs.open(new Path(filename))
val inputSteam=new InputStreamReader(dataInputStream, "UTF-8")
val br=new BufferedReader(inputSteam)
val bufferSize = 300
var buffer = Array.ofDim[Char](bufferSize)
var totalRead = 0

while ({
  // 读取剩余未填充的缓冲区位置
  val readCount = br.read(buffer, totalRead, bufferSize - totalRead)
  if (readCount == -1) {
    // 流已结束,退出循环
    false
  } else {
    totalRead += readCount
    // 如果缓冲区填满,处理这块数据并重置计数器
    if (totalRead == bufferSize) {
      val str = new String(buffer)
      println(bufferSize,"##", str)
      totalRead = 0
    }
    true
  }
}) {}

// 处理最后剩余的不足300字符的部分
if (totalRead > 0) {
  val str = new String(buffer, 0, totalRead)
  println(totalRead,"##", str)
}

这段代码的逻辑是:

  • 用totalRead跟踪缓冲区中已填充的字符数
  • 每次只读取缓冲区剩余的空位,直到缓冲区被填满或者流结束
  • 当缓冲区填满时,处理这块完整的300字符数据,然后重置totalRead
  • 循环结束后,处理最后剩余的不足300字符的部分

这样就能保证除了最后一块,每次都处理完整的300字符块。

内容的提问来源于stack exchange,提问作者Chaouki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 21:42:54