fs_shim 2.5.4+2 copy "fs_shim: ^2.5.4+2" to clipboard
fs_shim: ^2.5.4+2 copied to clipboard

A portable file system implementation working on io, web (OPFS or IndexedDB) and memory

fs_shim #

A portable file system library for Dart and Flutter.

fs_shim exposes a single asynchronous File/Directory/Link API (a subset of dart:io) that runs the same code on:

  • ๐Ÿ–ฅ Dart VM / Flutter native (IO)
  • ๐ŸŒ Web โ€” browser storage (through idb_shim)
  • ๐ŸŒ Web โ€” OPFS (Origin Private File System), a thin layer over the native browser API
  • ๐Ÿงช Tests / in-memory (through idb_shim)

API supported #

It contains a subset of the io File/Directory API. Basically all sync methods are removed since on the web indexedDB (and OPFS) cannot be accessed in a synchronous way. All operations are asynchronous and return a Future (or a Stream for openRead/list).

Classes

  • File (create, openWrite, openRead, writeAsBytes, writeAsString, copy)
  • Link (create, target)
  • Directory (create, list)
  • FileSystem (file, link, directory, type, isFile, isDirectory, isLink)
  • FileSystemEntity (path, exists, delete, rename, absolute, isAbsolute, stat, parent)
  • FileStat
  • FileSystemEntityType
  • FileSystemException

Static method

  • Directory.current
  • FileSystemEntity.isFile
  • FileSystemEntity.isDirectory
  • FileSystemEntity.isLink

Static and File/Directory/Link constructors use fileSystemDefault which is platform dependent (web or io).

Implementations #

File system Import Platform Links Random access
fileSystemDefault package:fs_shim/fs_shim.dart all io io / web
fileSystemIo package:fs_shim/fs_shim.dart io โœ…ยน โœ…
fileSystemMemory package:fs_shim/fs_shim.dart all โœ… โœ…
fileSystemWeb package:fs_shim/fs_browser.dart web โœ… โœ… (opt-in)
fileSystemOpfsWeb package:fs_shim/fs_opfs_web.dart web โŒ โŒ

ยน File links are not supported on Windows (fs.supportsFileLink returns false).

You can always check capabilities at runtime with fs.supportsLink, fs.supportsFileLink and fs.supportsRandomAccess.

Installation #

Add the following dependency to your pubspec.yaml:

dependencies:
  fs_shim: ^<latest>

Usage #

In memory #

A simple usage example:

import 'package:fs_shim/fs_shim.dart';
import 'package:path/path.dart';

Future<void> main() async {
  final fs = fileSystemMemory;

  // Create a top level directory
  final dir = fs.directory('/dir');

  // and a file in it
  final file = fs.file(join(dir.path, 'file'));

  // create a file
  await file.create(recursive: true);
  await file.writeAsString('Hello world!');

  // read a file
  print('file: ${await file.readAsString()}');

  // use a file link if supported
  if (fs.supportsFileLink) {
    final link = fs.link(join(dir.path, 'link'));
    await link.create(file.path);

    print('link: ${await fs.file(link.path).readAsString()}');
  }

  // list dir content
  print(await dir.list(recursive: true, followLinks: true).toList());
}

The same code runs unchanged against any other implementation: just swap the fs instance.

Using IO API #

Using fs_shim.dart

You can simply replace in the above example:

final fs = fileSystemMemory;

by

final fs = fileSystemIo;

If you only target io, you can still use the File and Directory constructors, replace

import 'dart:io'
    hide
    Directory,
    File,
    Link,
    FileSystemEntity,
    FileMode,
    FileStat,
    OSError,
    FileSystemException,
    FileSystemEntityType;

import 'package:fs_shim/fs_shim.dart';

by

import 'package:fs_shim/fs_io.dart';

Then a reduced set of the IO API can be used, same source code that might require some cleanup if you import from existing code.

Simple example

import 'package:fs_shim/fs_io.dart';
import 'package:path/path.dart';

Future<void> main() async {
  final fs = fileSystemDefault;
  // safe place when running from package root
  final dirPath = join(Directory.current.path, 'test_out', 'example', 'dir');

  // Create a top level directory
  final dir = Directory(dirPath);
  print('dir: $dir');
  // delete its content
  if (await dir.exists()) {
    await dir.delete(recursive: true);
  }

  // and a file in it
  final file = File(join(dir.path, 'file'));

  // create a file
  await file.create(recursive: true);
  await file.writeAsString('Hello world!');

  // read a file
  print('file: ${await file.readAsString()}');

  // use a file link if supported
  if (fs.supportsFileLink) {
    final link = Link(join(dir.path, 'link'));

    await link.create(basename(file.path));
    final linkFile = File(link.path);
    print('link: ${await linkFile.readAsString()}');
  }

  // list dir content
  print(await dir.list(recursive: true, followLinks: true).toList());
}

Browser usage #

You can simply replace in the in-memory example:

final fs = fileSystemMemory;

by

import 'package:fs_shim/fs_browser.dart';

final fs = fileSystemWeb;

The default implementation on the browser uses fileSystemWeb (backed by indexedDB through idb_shim).

OPFS usage (Origin Private File System) #

fs_shim also provides an implementation on top of the browser Origin Private File System (OPFS). It is a thin layer over the native navigator.storage.getDirectory() API (using dart:js_interop, so it is Wasm compatible).

import 'package:fs_shim/fs_opfs_web.dart';

final fs = fileSystemOpfsWeb;

There is a single OPFS per origin, so fileSystemOpfsWeb returns a shared instance. The same File/Directory code shown in the examples above runs unchanged on OPFS.

When to use OPFS instead of fileSystemWeb:

  • OPFS is backed directly by the browser's native file system primitives, which is well suited for storing larger files and binary content.
  • fileSystemWeb (indexedDB) supports links and (opt-in) random access, which OPFS does not.

Limitations of the OPFS implementation:

  • Links are not supported (fs.supportsLink / fs.supportsFileLink return false).
  • Random access is not supported (fs.supportsRandomAccess returns false).
  • Web only โ€” fileSystemOpfsWeb relies on navigator.storage.getDirectory(). The import is safe on any platform, but accessing the instance off the web is not supported.

Instead of the origin private root, a file system can also be rooted at any JS FileSystemDirectoryHandle (File System Access API), for example a directory picked by the user:

import 'package:fs_shim/fs_opfs_web.dart';
import 'package:web/web.dart';

final handle = await window.showDirectoryPicker().toDart; // Chromium-only
final fs = fileSystemOpfsWebWithRootHandle(handle);

The handle is used as-is (any interop binding works). Write operations require the handle to have been granted readwrite permission, and handles do not persist across page reloads unless saved by the application (e.g. in indexedDB) and permission requested again.

Random access support #

Random access is supported since version 2.1.0 on io and web (indexedDB).

The default web implementation is not optimized for random access (it might change in the future). You can specify a paging parameter (initial testing is good in some scenarios with a 16Kb page; you might tune it for your needs).

import 'package:fs_shim/fs_browser.dart';

// Use default paging 16Kb
final fs =
  fileSystemWeb.withIdbOptions(options: FileSystemIdbOptions.pageDefault);

Storage remains compatible if the options are changed.

Random access is not supported by the OPFS implementation.

Utilities #

  • Lightweight glob support (**, * and ? in a posix style path)
  • Copy utilities (copy files, directories recursively)

Testing #

fs_shim is well suited for testing file system access in VM unit tests using fileSystemMemory, then running the exact same code on io or the web.

Dev dependencies #

Stable

fs_shim: any

Bleeding edge

fs_shim:
    git: https://github.com/tekartik/fs_shim.dart

Features and bugs #

  • On Windows file links are not supported (fs.supportsFileLink returns false)

  • On Windows directory link targets are absolute

  • On the web (indexedDB), the size of the file system is limited by the size limit of indexedDB databases (browser dependent)

  • On the web (OPFS), links and random access are not supported

  • Project source code

10
likes
160
points
4.65k
downloads

Documentation

API reference

Publisher

verified publishertekartik.com

Weekly Downloads

A portable file system implementation working on io, web (OPFS or IndexedDB) and memory

Repository (GitHub)
View/report issues

Topics

#file-system #abstraction #storage #opfs

License

BSD-2-Clause (license)

Dependencies

idb_shim, meta, path, sembast, synchronized

More

Packages that depend on fs_shim