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
相关产品推荐
相关产品推荐

