Hi everyone! I am part of the Kotlin Libraries te...
# stdlib
a
Hi everyone! I am part of the Kotlin Libraries team. I would like to hear your feedback on the following path-related functions in the standard library: • Path.walk()Path.visitFileTree()fileVisitor()Path.copyToRecursively()Path.deleteRecursively() We are considering stabilizing them soon, so your feedback is very valuable. Did you have an opportunity to use them in your projects? How was your experience with them? Was there something confusing, unexpected, or annoying when using them? Or was everything smooth and intuitive?
e
Path.walk
default is depth first? I would probably highlight it in documentation. "Include directories" means that it is not going to walk subfolders by default, correct?
Interesting that
visitFileTree()
doesn't have breadth first option analogue
k
"Include directories" means that it is not going to walk subfolders by default, correct?
The way I've understood the documentation at first glance was that it would walk subfolders (and always would, no matter what options you gave) and that the "include directories" option would determine whether or not directory names would be returned in the results.
☝️ 1
One thing about the documentation: it's no longer necessary to include a coloured dot for "JRE7" as Kotlin no longer supports JRE6.
Another documentation problem: for copyToRecursively the
->
operator is split in two lines.
I haven't used these functions, but I'm wondering why
deleteRecursively
doesn't have an onError function like
copyToRecursively
. The
OnErrorResult
class seems well suited for that too.
c
I've used most of these and I can't remember any specific problems I had, so… nice that they'll be stabilized 🙂
p
Same here, we are using them for a while (including Gradle tasks) and no outstanding issue comes to mind. 😉
e
Haven't used - just looking on the documentation
a
Path.walk()
is significantly less useful than
File.walk()
• It's missing
onEnter {}
, so I can't dynamically prevent entering specific directories. • Can't do
maxDepth(5)
to limit the depth.
The documentation for the
Path.visitFileTree()
build stuff is not very helpful. E.g. onPreVisitDirectory. I don't think this doc practically explains the purpose and intended usage of the function:
Overrides the corresponding function of the built file visitor with the provided function.
I see a tiny typo in the
fileVisitor()
kdoc. It has > ``` kotlin but it should be > ```kotlin https://github.com/JetBrains/kotlin/blob/99b03cef10a0ebb63f55bf6a16390c28c1e96bbe/libraries/stdlib/jdk7/src/kotlin/io/path/PathUtils.kt#L1155C2-L1155C14 Because of the extra space the code block isn't syntax highlighted https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io.path/file-visitor.html
🙏 1
Path.visitFileTree()
can't be converted to a sequence :(
Copy code
sequence {
  myLocalPath.visitFileTree(maxDepth = 5) {
    onPreVisitDirectory { dir, _ ->
      if (dir.name != "foo") {
        CONTINUE
      } else {
        SKIP_SUBTREE
      }
    }
    onVisitFile { file, _ ->
      yield(file) // ERROR [NON_LOCAL_SUSPENSION_POINT] Suspension functions can be called only within coroutine body
      CONTINUE
    }
  }
}
c
should those functions be on the kotlinx.io Path / Filesystem as well? They already have
list
, the others visitors are variations on that.
k
Sorry for the late reply, but a new issue has just occurred to me. In Java,
Files.walk
should be done in a try-with-resources block because the returned
Stream<Path>
needs to be closed. The new Kotlin
Path.walk
function returns a
Sequence<Path>
which is not
AutoCloseable
. How do we release the resources from this sequence?
a
@Klitos Kyriacou
Path.walk
does not keep directories “open”, meaning it does not maintain `DirectoryStream`s. Therefore, there is no need to close them. See the implementation for details: https://github.com/JetBrains/kotlin/blob/256710895084b3a5d3ed97b16d208e1e6c1fc276/libraries/stdlib/jdk7/src/kotlin/io/path/PathTreeWalk.kt
k
I see, thanks for pointing that out. It looks good, but I can see some rare edge cases where it might be a slight problem. Imagine running
Path.walk
on a small device with very limited memory with a TCP connection to a server and reading a directory that contains a million files. It will have to read all of them in one go into a
List
.
a
We did think about such a scenario, and decided that the benefit of easy use in general cases outweighs the limited usability in rare cases.
f
(That's a timely response, huh?)
I haven't used these functions, but I'm wondering why
deleteRecursively
doesn't have an onError function like
copyToRecursively
. The
OnErrorResult
class seems well suited for that too.
@Klitos Kyriacou do you see any practical strategies to deal with errors occurred during removal (or, maybe, you have a scenario where it will be useful)? Or it's mostly about the coherence of these two functions?
k
@Filipp Zhinkin both for consistency with
copyToRecursively
and for better usability. On the latter point, I've seen many cases in Java where a less experienced developer used File.delete instead of Files.delete and had problems due to failing to detect that File.delete was unable to delete the file (or they knew that the file could not be deleted but didn't know why). In the case of
deleteRecursively
what should be done if a file in the middle of a list could not be deleted? Should it terminate immediately with an exception? Should it continue deleting the remaining other files and then throw the exception? Should it continue deleting the remaining files and swallow the exception? An
onError
function (with a sensible default such as `copyToRecursively`'s default) would give the developer a choice, and would also allow the developer to log a list of files that failed to be deleted, together with the reason for failure for each file. By the way, I've just noticed that the
copyToRecursively
return value is not documented.
gratitude thank you 1
f
Thank you for elaborating!