better-files icon indicating copy to clipboard operation
better-files copied to clipboard

IllegalStateException occurs when using `partition` on `File.glob` result

Open hmf opened this issue 7 years ago • 2 comments

The following code:

    val dir: File = cwd / "data/inegi/ensaios_rolamentos_3"
    val matchNames = "*.csv"

    val matches_tmp: Iterator[File] = dir.glob(matchNames)
    val (good, bad) = matches_tmp.partition{ e => e.path.getFileName.toString.contains("norm") }
    println(s"good.size = ${good.size}")
    println(s"bad.size = ${bad.size}")

Picks up 90 files. It should split the list into two 45 element lists. However this results in the following exception on the first size call.

java.lang.IllegalStateException:
[info]   at java.nio.file.FileTreeIterator.hasNext(FileTreeIterator.java:103)
[info]   at java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1811)
[info]   at java.util.stream.StreamSpliterators$WrappingSpliterator.lambda$initPartialTraversalState$0(StreamSpliterators.java:294)
[info]   at java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.fillBuffer(StreamSpliterators.java:206)
[info]   at java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.doAdvance(StreamSpliterators.java:169)
[info]   at java.util.stream.StreamSpliterators$WrappingSpliterator.tryAdvance(StreamSpliterators.java:300)
[info]   at java.util.Spliterators$1Adapter.hasNext(Spliterators.java:681)
[info]   at scala.collection.convert.Wrappers$JIteratorWrapper.hasNext(Wrappers.scala:39)
[info]   at better.files.Dispose$FlatMap$Implicits$traversableFlatMap$.$anonfun$apply$3(Dispose.scala:160)
[info]   at better.files.Implicits$IteratorExtensions$$anon$2.hasNext(Implicits.scala:60)

One can circumvent the issue by converting the iterator so:

    val (good, bad) = matches_tmp.toList.partition{ e => e.path.getFileName.toString.contains("norm") }

Using Scala 2.12.6 and the latest version of better-files.

hmf avatar Oct 17 '18 16:10 hmf

Hello, Thank you for the report!

This could be reproduced and reduced to simple directory walk (and ultimately to the java.nio.file.Files.Walk):

      // result would be java.lang.IllegalStateException:
      // val result: Iterator[File] = dir.listRecursively()

      // this will work
      val result: Iterator[File] = dir.listRecursively().toSeq.toIterator

      val (good, bad) = result.partition{ e => e.path.getFileName.toString.contains("a") }

      println(s"good.size = ${good.size}")
      println(s"bad.size = ${bad.size}")

toSeq.toIterator would "fix" this with API compatible way in walk of better-files. But then there would be invisible toSeq, which is not nice. I don't know offhand how to fix this at Java level.

jaa127 avatar Oct 21 '18 19:10 jaa127

Reopenning this since this is almost impossible to fix. Since these iterators are "autoclosing" (i.e. they close underlying resource). So when we "partition them" we are sharing a resource between 2 iterators and when first one finishes it closes that resource making the 2nd one throw this exception

pathikrit avatar Feb 24 '19 06:02 pathikrit