Сайт

Файловая система

У sdk.fs три области: произвольное чтение файлов по пути, доступ на чтение и запись к папке вашего расширения и доступ только для чтения к другим расширениям. Файлы и папки, которые пользователь выбирает в диалоге, доступны через дескрипторы — см. файловые диалоги.

Чтение по пути

readFile(path: string): Promise<Uint8Array>
readFile(path: string, encoding: 'utf-8' | 'base64'): Promise<string>

Область на основе пути читает любой файл, к которому имеет доступ приложение, используя абсолютный путь или URI. Строка, содержащая ://, разбирается как URI (например, file:///…); всё остальное считается путём к файлу. Разрешение не требуется.

| encoding | Результат | | --- | --- | | не задан | Сырые байты в виде Uint8Array. | | 'utf-8' | Файл, декодированный как текст. | | 'base64' | Байты файла в виде Base64-строки. |

Папка вашего расширения

Методы sdk.fs.extension.* работает с путями относительно папки установки вашего расширения (context.extensionPath), используйте её как хранилище вашего расширения.

readFile(path: string): Promise<Uint8Array>
readTextFile(path: string): Promise<string>
readDir(path: string): Promise<ReadDirEntry[]>
exists(path: string): Promise<boolean>
stat(path: string): Promise<FileStats | null>
writeFile(path: string, content: Uint8Array | string, options?: WriteFileOptions): Promise<void>
mkdir(path: string, options?: MkdirOptions): Promise<void>
rmdir(path: string, options?: RmdirOptions): Promise<void>
unlink(path: string): Promise<void>
rename(from: string, to: string): Promise<void>
await sdk.fs.extension.mkdir('output')
await sdk.fs.extension.writeFile('output/result.json', JSON.stringify(result))

Перед использованием пути нормализуются:

  • \ считается /, повторяющиеся слэши схлопываются в один.
  • Ведущие ./ и / отбрасываются — /data.json означает data.json в вашей папке.
  • '' и . означают саму папку.
  • Любой сегмент .. отклоняется, даже если результат остался бы внутри папки (a/../b).

| Метод | Поведение | | --- | --- | | readFile / readTextFile | Байты или текст, декодированный как UTF-8. | | readDir | Записи директории: { name, type }. | | exists | true, если запись существует. | | stat | { name, size, type } или null, если записи нет или её не удалось прочитать. | | writeFile | string записывается как UTF-8, Uint8Array — как байты. Без options используется { create: true, overwrite: true } — файл создаётся или заменяется, недостающие родительские папки создаются. Переданные options заменяют это значение по умолчанию, так что задавайте create и overwrite сами. | | mkdir | Без options используется { recursive: true } — недостающие родительские папки создаются. Переданные options заменяют это значение по умолчанию. | | rmdir | Удаляет пустую директорию; с { recursive: true } — вместе с содержимым. | | unlink | Удаляет файл. | | rename | Перемещает или переименовывает внутри вашей папки; оба пути подчиняются правилам выше. |

С create: false writeFile падает, если файла нет; с overwrite: false — если файл уже существует.

ReadDirEntry · FileStats
type FileType = 'file' | 'directory' | 'symbolicLink' | 'unknown'

interface ReadDirEntry {
  name: string
  type: FileType
}

interface FileStats {
  name: string
  size: number   // размер в байтах
  type: FileType
}
WriteFileOptions · MkdirOptions · RmdirOptions
interface WriteFileOptions {
  encoding?: BufferEncoding // кодировка для строкового содержимого
  mode?: number             // режим файла (права доступа)
  flag?: string             // флаг файловой системы, например 'a' для дозаписи
  create?: boolean          // создать файл, если его нет
  overwrite?: boolean       // заменить файл, если он существует
}

interface MkdirOptions {
  recursive?: boolean       // создать недостающие родительские директории
  mode?: number             // режим директории (права доступа)
}

interface RmdirOptions {
  recursive?: boolean       // удалить директорию вместе с содержимым
}

Другие расширения (read-only)

Методы sdk.fs.extensions.* читают файлы другого установленного расширения по его id. Требуется разрешение fs:extensions — см. как работает запрос.

readFile(extensionId: ExtensionId, path: string): Promise<Uint8Array>
readTextFile(extensionId: ExtensionId, path: string): Promise<string>
readDir(extensionId: ExtensionId, path: string): Promise<ReadDirEntry[]>
exists(extensionId: ExtensionId, path: string): Promise<boolean>
stat(extensionId: ExtensionId, path: string): Promise<FileStats | null>
{ "contributes": { "permissions": ["fs:extensions"] } }

Пути задаются относительно папки установки целевого расширения и подчиняются тем же правилам, что указаны выше. Разрешение проверяется при вызове каждого метода, включая exists и stat.

Именно так оркестратор читает deployment_manifest.json из расширений с node-паками, используемыми на холсте:

const used = await sdk.project.nodeEditor.getUsedNodeExtensions()
for (const ext of used) {
  const manifest = await sdk.fs.extensions.readTextFile(ext.id, 'deployment_manifest.json')
}

Ошибки

Вызовы отклоняются, когда:

  • путь содержит сегмент ..;
  • целевое расширение sdk.fs.extensions не установлено;
  • fs:extensions не объявлено или пользователь отклонил разрешение;
  • сама файловая операция не удалась (файла нет, нет доступа и т. п.) — кроме stat, который возвращает null.