FAQ¶
I have a SAF directory permission — how do I read/write/delete files in it?¶
Through this package's API, not dart:io. A SAF grant is accessed only via
the SAF content API, so File(path) from dart:io fails on a granted folder.
Everything you need is on the Saf class:
final doc = await saf.writeFileBytes(dir.uri, 'a.txt', 'text/plain', bytes); // create/write
final data = await saf.readFileBytes(doc.uri); // read
await saf.rename(doc.uri, 'b.txt'); // update (rename)
await saf.delete(doc.uri); // delete
No second package and no raw MethodChannel calls — see Recipes.
Why is saf Android-only?¶
The Storage Access Framework is an Android API. There is no cross-platform
equivalent, so a faithful SAF binding is Android-only by nature. On other
platforms use dart:io / path_provider / file_picker.
Do I still need permission_handler?¶
No. saf 2.x does not depend on it, and SAF itself needs no runtime storage
permission — access is granted through the system picker. Add permission_handler
directly only if the rest of your app uses it.
How do I avoid re-prompting on every launch?¶
Grants are persisted by default. On startup, check persistedPermissions() and
reuse a grant instead of calling pickDirectory() again:
final grants = await saf.persistedPermissions();
if (grants.isNotEmpty) {
final dir = await saf.stat(grants.first.uri);
}
isDynamic: false used to break — is that fixed?¶
That was the old LegacySaf behavior. The new Saf API is URI-based and does
not have isDynamic; it adopts whatever directory the user grants and reuses it
across restarts.
Can I read very large files?¶
Yes — use readFileStream and process chunks as they arrive.
Backpressure
readFileStream uses Flutter's EventChannel, which does not apply
backpressure. If your consumer is much slower than disk, lower bufferSize
to cap peak memory. (This limitation is shared with other SAF streaming
packages.)
Does overwrite always truncate?¶
saf opens overwrites in truncate mode ("wt"), which conforming providers
honor. A few third-party DocumentsProviders ignore the truncate flag; if you
overwrite with shorter content on such a provider, delete first to be safe.
Where's the full API reference?¶
The generated dartdoc lives at jvoltci.github.io/saf/api.