Orientação gerada a partir de informações públicas. Apenas para referência.
Uma biblioteca Dart que expõe a API de Acesso ao Sistema de Arquivos da Plataforma Web, permitindo que aplicativos web leiam e escrevam com segurança no sistema de arquivos local dos usuários. Ela oferece uma abordagem moderna baseada em permissões para manipulação de arquivos, alinhando-se às capacidades do navegador. O pacote simplifica as interações com arquivos e diretórios por meio de interfaces intuitivas em Dart, melhorando a experiência do usuário em aplicações web que exigem manipulação de arquivos. É projetado especificamente para plataformas web e utiliza APIs nativas do navegador quando disponíveis.
Casos de uso
Lendo e escrevendo arquivos diretamente do armazenamento local do usuário
Criando aplicativos da web com recursos avançados de gerenciamento de arquivos
Habilitar operações de arrastar e soltar arquivos em aplicativos da web
Criando aplicativos da web com foco em offline com acesso persistente a arquivos
Permitir que os usuários salvem arquivos sem depender de prompts de download
Principais recursos
Integração direta com a API de Acesso ao Sistema de Arquivos do navegador
Acesso ao sistema de arquivos com base em permissões
Suporta leitura e escrita de arquivos e diretórios
Boilerplate mínimo para operações de arquivo comuns
Suporte de plataforma exclusivo para Web
Indicado para
Desenvolvedores web construindo aplicações centradas em arquivos
Aplicativos que exigem acesso seguro aos arquivos controlados pelo usuário
Desenvolvedores direcionados para navegadores modernos com capacidades de sistema de arquivos
Projetos que precisam de interação contínua com arquivos sem viagens ao servidor
Usuários do Flutter Web procurando comportamento de sistema de arquivos nativo
Considerações
Funciona apenas em plataformas da web
Requer navegadores modernos com suporte à API de Acesso ao Sistema de Arquivos
As permissões do usuário devem ser concedidas para operações de arquivo
Opções limitadas de fallback para navegadores antigos
Incompatível com alvos móveis ou de desktop do Flutter
README original
Snapshot do README original do repositório-fonte vinculado. Consulte o repositório para o conteúdo mais recente.
File System Access API
A Dart library to expose the File System Access API from web platform.
You can pick files and directories from user's file system to read, write, create, move and delete files/directories
from Dart web apps.
The web API (and this library) is experimental and is only supported on Chrome, Edge and Opera browsers for now.
It is not recommended to use this library in a production environment.
Features
This library reflects the web File System Access API using Dart types.
See a more detailed description on MDN Web Docs or keep reading to Usage section below.
Getting started
Install library in your Dart project:
$ dart pub add file_system_access_api
You're all set to play around with the API.
Note that in a cross-platform Flutter project, you can use this library only in a Web environment.
Use kIsWeb to prevent building/runtime errors and optimize build size.
Usage
You can reproduce example from the web API as much of the interfaces are transparent between this Dart library and the
JavaScript API.
Is browser supported
You can check if current browser supports the File System Access API with:
voidmain() {
if (!FileSystemAccess.supported) {
print("Browser does not support API.");
return;
}
print("Browser support API.");
}
Note that you must execute code samples below within main() as a result of a user gesture (e.g. click event) for
security reason. This part is omitted for brevity.
Open file(s)
You can ask a user to open file(s) with the method window.showOpenFilePicker() and access selected files like this:
voidmain() async {
try {
List<FileSystemFileHandle> handles = awaitwindow.showOpenFilePicker(
multiple: true,
excludeAcceptAllOption: true,
types: [FilePickerAcceptType(description: "Pictures", accept: {"image/png+jpg": [".png", ".jpg"]})],
startIn: WellKnownDirectory.pictures
);
for (final handle in handles) {
File file = await handle.getFile();
print("<file name='${handle.name}' size='${file.size} bytes' />");
// You can read content of a File using a FileReader, like any other File coming from 'dart:html'
}
} onAbortError {
print("User dismissed dialog or picked a file deemed too sensitive or dangerous.");
}
}
Save a file
You can ask a user where to save a file with the method window.showSaveFilePicker() and write in the selected file
like this:
voidmain() async {
try {
FileSystemFileHandle handle = awaitwindow.showSaveFilePicker(
suggestedName: "awesome.dart",
excludeAcceptAllOption: true,
types: [FilePickerAcceptType(description: "Dart files", accept: {"application/dart": [".dart"]})],
startIn: WellKnownDirectory.documents
);
FileSystemWritableFileStream stream = await handle.createWritable();
await stream.writeAsText(
"void main() {"" print('This is the way.');""}"
);
await stream.close();
// Note that data will be written on disk only after call to close() completed.
} onAbortError {
print("User dismissed dialog or picked a file deemed too sensitive or dangerous.");
} onNotAllowedError {
print("User did not granted permission to readwrite in this file.");
}
}
Open a directory
You can ask a user to pick a directory window.showDirectoryPicker() and recursively access files and directories like
this:
voidmain() async {
try {
FileSystemDirectoryHandle directory = awaitwindow.showDirectoryPicker(
// Use readwrite to ask permission and grant write access on files instead.
mode: PermissionMode.read
);
// List of handles in a directory emitted with a [Stream].// Listen periodically on [Stream] to reproduce a file system watch-like feature.awaitfor (FileSystemHandle handle in directory.values) {
if (handle.kind == FileSystemKind.file) {
print("<file name='${handle.name}' />");
} elseif (handle.kind == FileSystemKind.directory) {
print("<directory name='${handle.name}/' />");
// You can create, move and delete files/directories. See example/ for more on this.
}
}
} onAbortError {
print("User dismissed dialog or picked a directory deemed too sensitive or dangerous.");
}
}
Permissions
You can query / request permission on files and directories from the user. It allows you to write in files, modify a
directory structure, etc. Those methods are available per file/directory handle:
voidmain() async {
try {
final handles = awaitwindow.showOpenFilePicker(multiple: false);
final handle = handles.single;
var permission = await handle.queryPermission(mode: PermissionMode.readwrite);
if (permission != PermissionState.granted) {
print("Asking permission to read and write");
permission = await handle.requestPermission(mode: PermissionMode.readwrite);
if (permission != PermissionState.granted) {
print("read/write access refused, either prompt was dismissed or denied.");
return;
}
print("read/write access granted. 😀");
}
print("Write beautiful bytes. ✨");
} onAbortError {
print("User dismissed dialog or picked a file deemed too sensitive or dangerous.");
}
}
Note that current implementation of the File System Access API does not remember permissions across browser's sessions
when used with IndexedDB.
Star crbug.com/1011533 to be notified of work on persisting granted permissions.
Drag and Drop
You can get files/directories from a drag-n-drop event:
voidmain() {
final $area = document.querySelector("#area") asDivElement;
$area.addEventListener("dragover", (event) => event.preventDefault());
$area.addEventListener("drop", (event) async {
event.preventDefault();
final handles = awaitFileSystemAccess.fromDropEvent(event);
for (final handle in handles) {
print("<${handle.kind.name} name='${handle.name}' />");
}
});
}
Remove handle
Experimental and non-standard.
You can remove a file/directory directly from its handle, instead of using the handle of the parent directory:
FileSystemHandle handle;
if (handle.kind == FileSystemKind.file) {
final file = handle asFileSystemFileHandle;
print("handle is a file");
} elseif (handle.kind == FileSystemKind.directory) {
final directory = handle asFileSystemDirectoryHandle;
print("handle is a directory.");
}
How to compare FileSystemHandle(s)
DON'T compare using == operator or hashCode property:
FileSystemFileHandle a;
FileSystemFileHandle b;
if (a == b) {
print("will return false even when a and b represents the same file entry.");
}
DO compare using FileSystemHandle.isSameEntry:
voidmain() async {
FileSystemFileHandle a;
FileSystemFileHandle b;
if (await a.isSameEntry(b)) {
print("return true when a and b represents the same file entry.");
}
}
More
See examples in example/ folder to play with fun tools.
Origin Private File System
This is a storage endpoint private to the origin of the page. It contains files/directories within a "virtual disk"
chosen by the browser implementing this API. Files and directories may be written in a database or any other data
structure. You should not expect to find those files/directories as-this on the hard disk.
Get root directory
You can get a root directory of the origin private file system with:
Applies only within a Web Worker and Origin Private File System for now.
You can get an interface to synchronously read from and write to a file. This will create an exclusive lock on the file
associated with the file handle, until it is closed:
// Code executed within a Web Workervoidmain() async {
FileSystemDirectoryHandle root;
FileSystemFileHandle source = await root.getFileHandle("linux.iso");
FileSystemSyncAccessHandle src = await source.createSyncAccessHandle();
Uint8List buffer = Uint8List(src.getSize());
src.read(buffer);
src.close();
print(buffer);
}
Missing features
It's all good for now.
Known issues
You cannot store a FileSystemHandle into IndexedDB as-this. See issue #50621 for more. A workaround is implemented
in LightStorage within example/ folder.