패키지, 저장소 및 앱 카테고리 검색

패키지 상세v2.0.0

file_system_access_api

웹 플랫폼에서 파일 시스템 액세스 API를 노출하기 위한 Dart 라이브러리입니다.

Web
30일 다운로드
9천
좋아요
27
Pub 점수
120

패키지 설치

flutter pub add file_system_access_api

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

웹 플랫폼의 파일 시스템 액세스 API를 노출하는 Dart 라이브러리로, 웹 애플리케이션이 사용자의 로컬 파일 시스템에서 안전하게 읽고 쓸 수 있도록 합니다. 현대적인 권한 기반 접근 방식을 제공하여 브라우저의 기능과 일치합니다. 패키지는 직관적인 Dart 인터페이스를 통해 파일 및 디렉터리와의 상호작용을 단순화하여 파일 조작이 필요한 웹 앱의 사용자 경험을 향상시킵니다. 웹 플랫폼 전용으로 설계되었으며, 가능할 경우 네이티브 브라우저 API를 활용합니다.

사용 사례

  • 사용자의 로컬 스토리지에서 파일을 직접 읽고 쓰기
  • 고급 파일 관리 기능을 갖춘 웹 앱 구축
  • 웹 애플리케이션에서 드래그 앤 드롭 파일 작업을 활성화하는 방법
  • 지속적인 파일 접근을 활용한 오프라인 우선 웹 애플리케이션 만들기
  • 다운로드 프롬프트에 의존하지 않고 사용자가 파일을 저장할 수 있도록 허용

주요 기능

  • 브라우저의 파일 시스템 액세스 API와의 직접 통합
  • 권한 기반 파일 시스템 접근
  • 파일 및 디렉터리의 읽기 및 쓰기 모두를 지원합니다
  • 일반적인 파일 작업을 위한 최소한의 뼈대 코드
  • 웹 전용 플랫폼 지원

적합한 대상

  • 파일 중심 애플리케이션을 구축하는 웹 개발자
  • 보안 사용자 제어 파일 액세스가 필요한 앱
  • 파일 시스템 기능을 갖춘 현대 브라우저를 대상으로 하는 개발자
  • 서버 라운드트립 없이 원활한 파일 상호작용이 필요한 프로젝트
  • 네이티브 파일 시스템 동작을 원하는 Flutter Web 사용자

고려 사항

  • 웹 플랫폼에서만 작동합니다
  • 파일 시스템 액세스 API를 지원하는 최신 브라우저가 필요합니다
  • 파일 작업을 위해 사용자 권한이 부여되어야 합니다
  • 구형 브라우저용 제한된 백업 옵션
  • 모바일 또는 데스크톱 플러터 대상과 호환되지 않습니다

원본 README

연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.

File System Access API

Pub Version Platform Web License MIT Donate

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:

void main() {
  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:

void main() async {
  try {
    List<FileSystemFileHandle> handles = await window.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'
    }
  } on AbortError {
    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:

void main() async {
  try {
    FileSystemFileHandle handle = await window.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.
  } on AbortError {
    print("User dismissed dialog or picked a file deemed too sensitive or dangerous.");
  } on NotAllowedError {
    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:

void main() async {
  try {
    FileSystemDirectoryHandle directory = await window.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.
    await for (FileSystemHandle handle in directory.values) {
      if (handle.kind == FileSystemKind.file) {
        print("<file name='${handle.name}' />");
      } else if (handle.kind == FileSystemKind.directory) {
        print("<directory name='${handle.name}/' />");
        // You can create, move and delete files/directories. See example/ for more on this.
      }
    }
  } on AbortError {
    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:

void main() async {
  try {
    final handles = await window.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. ✨");
  } on AbortError {
    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:

void main() {
  final $area = document.querySelector("#area") as DivElement;
  
  $area.addEventListener("dragover", (event) => event.preventDefault());
  $area.addEventListener("drop", (event) async {
    event.preventDefault();
    
    final handles = await FileSystemAccess.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:

void main() async {
  FileSystemFileHandle file;
  FileSystemDirectoryHandle directory;
  
  await file.remove();
  await directory.remove(recursive: true);
}
How to cast a FileSystemHandle

DON'T test and cast using is keyword:

FileSystemHandle handle;

if (handle is FileSystemFileHandle) {
  print("will always return false");
} else if (handle is FileSystemDirectoryHandle) {
  print("will always return false");
}

DO test and cast using FileSystemHandle.kind:

FileSystemHandle handle;

if (handle.kind == FileSystemKind.file) {
  final file = handle as FileSystemFileHandle;
  
  print("handle is a file");
} else if (handle.kind == FileSystemKind.directory) {
  final directory = handle as FileSystemDirectoryHandle;
  
  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:

void main() 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:

void main() async {
  FileSystemDirectoryHandle? root = await window.navigator.storage?.getDirectory();
}
Rename a file

Applies only within Origin Private File System for now.

You can rename a file with:

void main() async {
  FileSystemDirectoryHandle root;

  FileSystemFileHandle handle = await root.getFileHandle("some-name.txt");

  await handle.rename("new-name.txt");
}
Move a file

Applies only within Origin Private File System for now.

You can move a file inside another directory and optionally rename it in the same call with:

void main() async {
  FileSystemDirectoryHandle root;
  
  FileSystemFileHandle handle = await root.getFileHandle("some-name.txt");
  FileSystemDirectoryHandle destination = await root.getDirectoryHandle("config", create: true);

  // Move only
  await handle.move(destination);
  // Move and rename
  await handle.move(destination, name: "new-name.txt");
}

Synchronous access in Web Workers

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 Worker
void main() 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.

File any potential issues you see.

Additional information

See this article on web.dev for an introduction to this API (JavaScript).

See examples and more on MDN Web Docs (JavaScript).

See specification on W3C WICG’s File System Access and WHATWG's File System.

Feel free to contribute with issues or pull-requests.

Intellectual property rights

This library includes documentation copied and/or modified from W3C WICG’s File System Access, which is available under the W3C Software and Document License.

This library includes documentation copied and/or modified from MDN Web Doc’s File System Access, by Mozilla Contributors which is available under the CC-BY-SA 2.5.

This library is available under MIT license.

카테고리

의존성

의존성 목록 1 개

  • js^0.7.0

소스 저장소

이 패키지를 사용하는 프로젝트

아직 데이터가 없습니다.