昨天,这段代码让我头疼.我通过逐行读取文件来修复它.有任何想法吗 ?
即使文件中的行数大于1,while循环也似乎永远不会被执行.
val lines = Source.fromFile( new File("file.txt") ).getLines;
println( "total lines:"+lines.size );
var starti = 1;
while( starti < lines.size ){
val nexti = Math.min( starti + 10, lines.size );
println( "batch ("+starti+", "+nexti+") total:" + lines.size )
val linesSub = lines.slice(starti, nexti)
//do something with linesSub
starti = nexti
}
Run Code Online (Sandbox Code Playgroud)
0__*_*0__ 14
这确实很棘手,我甚至会说这是一个错误Iterator.getLines返回Iterator懒惰进行的.所以似乎发生的事情是,如果你要求lines.size迭代器遍历整个文件来计算行数.之后,它"筋疲力尽":
scala> val lines = io.Source.fromFile(new java.io.File("....txt")).getLines
lines: Iterator[String] = non-empty iterator
scala> lines.size
res4: Int = 15
scala> lines.size
res5: Int = 0
scala> lines.hasNext
res6: Boolean = false
Run Code Online (Sandbox Code Playgroud)
你看,当你执行size两次时,结果为零.
有两种解决方案,要么将迭代器强制为"稳定",就像lines.toSeq.或者你忘了size并进行"正常"迭代:
while(lines.hasNext) {
val linesSub = lines.take(10)
println("batch:" + linesSub.size)
// do something with linesSub
}
Run Code Online (Sandbox Code Playgroud)
以上所有答案都没有达到头上的钉子.
这Iterator是一个很好的理由回到这里.通过延迟,它会从堆中获取压力,然后表示每行的String可以在完成后立即进行垃圾回收.对于大文件,这可以避免OutOfMemoryException的所有区别.
理想情况下,您可以直接使用迭代器,而不是强制它进入严格的集合类型.
使用grouped的话,按OM-NOM-NOM的回答:
for (linesSub <- lines grouped 10) {
//do something with linesSub
}
Run Code Online (Sandbox Code Playgroud)
如果你想保留println计数器,请在索引中压缩:
for ( (linesSub, batchIdx) <- (lines grouped 10).zipWithIndex ) {
println("batch " + batchIdx)
//do something with linesSub
}
Run Code Online (Sandbox Code Playgroud)
如果你真的需要总数,请调用getLines两次.一次计数,第二次实际处理线.