Build1 distinct publisher3 min readUpdated
A practitioner's account of building a filesystem abstraction shows where the seam has to sit: both access chains end in a stream, and almost nothing before the stream travels.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
The seam worth arguing about is the single place the two access chains agree: both of them end in a stream [4]. Before that, one has a path that becomes a `File`, and the other has a URI that becomes a `ContentResolver` or `DocumentsContract` call into a provider [3][4]. That fixes the limit of what a cross-platform storage layer can honestly promise. Handing back an `InputStream` travels [14]. Doing arithmetic on names does not [7].
The worked example in the post is worth counting. A library whose API takes `documents/example.txt` gets that for free on the JVM, where the string is a path to something on a filesystem [7]. Under a user-selected SAF tree, the same string has to be walked: the selected root, then `Documents`, then `projects`, then the file [9], and each step is a document-provider operation rather than a traversal of a mounted filesystem [8]. Three segments below the root, three provider operations [10]. The string also carries no handle to any of the intermediate documents [7], so anything resembling a working directory, or a cache of resolved parents, is something the library has to invent rather than something the platform hands over.
The indirection that makes this expensive is the same indirection the author praises. A granted document tree may be backed by a provider that is not local device storage at all, possibly remote or cloud-backed, and the application does not need to know which [6]. The post calls that one of the most powerful ideas behind SAF [6], and in the next breath warns that an abstraction which tries to hide every difference can be made worse by the hiding [12]. Those two positions are compatible only if the leak is deliberate: the layer resolves, opens and streams, and refuses to pretend it can tell you a parent path.
Which is why the count of five is a ceiling rather than a requirement. The post's own routing is narrow: application data belongs in application-private storage, supported shared media belongs in MediaStore, and SAF earns its keep when the requirement is specifically that a user picks a directory and the application then works inside it [5]. Strip that requirement and two models cover the app, not five [13]. Scoped storage is described as having made storage simpler for many applications for exactly this reason, since private directories plus the appropriate platform APIs remove the need for unrestricted access to the user's shared filesystem [11].
The cost, then, sits in an application's internal vocabulary rather than in any API surface. Code that passes `String` paths between its own modules has already decided it is running on a filesystem. This is one practitioner's account of building such a library [c2b], not a platform announcement, and the supplied text breaks off mid-sentence on the question of how much difference an abstraction should hide [12].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
A modern Android application may interact with application-private storage, shared media through MediaStore, user-selected documents through the Storage Access Framework (SAF), cloud-backed document providers, and traditional JVM filesystem APIs.
The author writes that the difficult part is not learning any one of these APIs, but building software that can work with different kinds of storage without forcing the entire application to understand the differences.
The author says that problem is what led them to build a filesystem abstraction for Android and the JVM.
Under SAF an application can receive something like content://com.android.externalstorage.documents/tree/primary%3ADocuments, which is not a filesystem path but a URI representing a document-provider resource; it is not meaningfully resolved with File(uri.path), and the operating system expects interaction through APIs such as ContentResolver and DocumentsContract.
The traditional chain is Path to File to InputStream/OutputStream; the SAF chain is URI to ContentResolver/DocumentsContract to Provider to InputStream/OutputStream. The final result may still be a stream, but everything before that stream is different.
Not every Android application needs SAF: if an application only needs its own application data it should use application-private storage, if it needs supported shared media MediaStore may be the right solution, and SAF becomes interesting when the requirement is to let the user choose a directory and work with files inside it.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Coherent mechanism, one self-published source
The technical core is specific and internally consistent: concrete content:// tree URI, named platform APIs (ContentResolver, DocumentsContract, DocumentFile), both access chains diagrammed, and a worked segment-by-segment resolution example. But it is a single self-published practitioner post with no repository, no platform documentation citation, no version scoping, and no measurements, and the supplied body ends mid-example.
No adoption evidence supplied
The author says they built a filesystem abstraction for Android and the JVM, but the cluster contains no name, release, package, download, deployment, or user disclosure for it, and no data on how widely SAF-based abstractions are used. Nothing in the supplied material supports an adoption measurement.
Mostly measured, mildly self-favouring
Framing is unusually restrained for the genre: the post explicitly says not every app needs SAF and that hiding every difference makes abstractions worse, which pulls the gap toward zero. It tips slightly positive because superlative framing ('one of the most powerful ideas behind SAF') and the implied need for the author's own abstraction rest on an unnamed, undemonstrated library with no adoption or performance evidence behind it.
Author promoting own abstraction
The narrative is authored by the builder of the very abstraction it argues for, published on a developer-brand platform where such posts serve visibility; that is a moderate, visible self-interest. It is not vendor-funded, no product is being sold or even named, and the piece concedes cases where its premise does not apply, which caps the score near the middle.
Plausible mechanics, unverified specifics
Confidence is limited by structure rather than content quality: one publisher, one self-interested author, no corroborating documentation or code, no adoption dimension available, and truncated text. The claims that describe platform mechanics are internally consistent and checkable in principle, which keeps confidence from falling lower.
build
"No key, no SDK" is not a guarantee on Android: the manifest merger gets there first1 distinct publisher
build
Geofencing beats GPS polling on power, then loses to the OEM battery optimiser1 distinct publisher
build
One game, two codebases: where parity belongs when you ship native on iOS and Android1 distinct publisher
build
SMS OTP as a ledger entry: one challenge, one send, and a server that owns expiry1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 23, 2026