Можно ли добавить к существующему файлу с помощью API доступа к файловой системе Chrome

Используя новый File System Access APIможно читать и записывать файлы и папки на устройстве пользователя:

      const newHandle = await window.showSaveFilePicker();
const writableStream = await newHandle.createWritable();
await writableStream.write("Hello World")
await writableStream.close();

Приведенный выше код напишет "Hello World" в выбранный файл. Если файл уже существует, он будет усечен и перезаписан новым содержимым.

Можно ли вместо этого добавить к существующему файлу, не читая весь файл и не записывая его снова? Хорошим примером может быть запись в файл журнала.

2 ответа

Джо Дункан прав (и спасибо за подсказку!)

Но вам нужно открыть записываемый файл в режиме «добавить».

Мне нужно закрыть/сбросить файл после записи каждой строки, а затем снова открыть, искать и добавлять в этот файл (но только 1 щелчок на кнопке «Сохранить файл»)

      import {} from "wicg-file-system-access"

/**
 * Supply a button-id in HTML, when user clicks the file is opened for write-append.
 * 
 * Other code can: new LogWriter().writeLine("First line...") 
 * to queue writes before user clicks the button.
 * 
 * file is flushed/closed & re-opened after every writeLine.
 * (so log is already saved if browser crashes...)
 */
export class LogWriter {
  fileHandle: FileSystemFileHandle;
  writeablePromise: Promise<FileSystemWritableFileStream> = this.newWriterPromise;
  writerReady: (value: FileSystemWritableFileStream | PromiseLike<FileSystemWritableFileStream>) => void 
  writerFailed: (reason?: any) => void
  contents: string
  get newOpenPromise () { return new Promise<FileSystemWritableFileStream>((fil, rej)=>{
    this.writerReady = fil; 
    this.writerFailed = rej
  })}
  constructor(name = 'logFile', public buttonId = "fsOpenFileButton") {
    const options = {
      id: 'logWriter',
      startIn: 'downloads', // documents, desktop, music, pictures, videos
      suggestedName: name,
      types: [{
          description: 'Text Files',
          accept: { 'text/plain': ['.txt'], },
        }, ],
    };
    this.setButton('showSaveFilePicker', options, (value) => {
      this.fileHandle = value as FileSystemFileHandle
      this.openWriteable()
    })
  }
  async openWriteable(fileHandle: FileSystemFileHandle = this.fileHandle,
    options: FileSystemCreateWritableOptions = { keepExistingData: true }) {
    let writeable = await fileHandle.createWritable(options)
    let offset = (await fileHandle.getFile()).size
    writeable.seek(offset)
    this.writerReady(writeable)
  }
  async writeLine(text: string) {
    try {
      let line = `${text}\n`
      let stream = (await this.openPromise) // indicates writeable is ready
      await stream.seek((await this.fileHandle.getFile()).size)
      await stream.write({type: 'write', data: line});
      let closePromise = this.closeFile()       // flush to real-file
      this.openPromise = this.newOpenPromise    // new Promise for next cycle:
      await closePromise
      while (!this.openPromise.value) await this.openWriteable()
    } catch (err) {
      console.warn(stime(this, `.writeLine failed:`), err)
      throw err
    }
  }
  async closeFile() {
    try {
      return (await this.writeablePromise).close();
    } catch (err) {
      console.warn(stime(this, `.closeFile failed:`), err)
      throw err
    }
  }
  /** multi-purpose picker button: (callback arg-type changes) */
  setButton(method: 'showOpenFilePicker' | 'showSaveFilePicker' | 'showDirectoryPicker',
    options: OpenFilePickerOptions & { multiple?: false; } & SaveFilePickerOptions & DirectoryPickerOptions,
    cb: (fileHandleAry: any) => void) {
    const picker = window[method]  // showSaveFilePicker showDirectoryPicker
    const fsOpenButton = document.getElementById(this.buttonId)
    fsOpenButton.innerText = method.substring(4, method.length - 6)
    fsOpenButton.onclick = () => {
      picker(options).then((value: any) => cb(value), (rej: any) => {
        console.warn(`showOpenFilePicker failed: `, rej)
      });
    }
    return fsOpenButton
  }
}

Вы можете получить текущий размер файла и установить позицию записи до конца:

      const newHandle = await window.showSaveFilePicker();
const writableStream = await newHandle.createWritable();

// Get the current file size.
const size = (await fileHandle.getFile()).size;

await writableStream.write({
  type: "write",
  data: "Hello World",
  position: size // Set the position to the current file size.
})
await writableStream.close();

Больше информации:

https://developer.mozilla.org/en-US/docs/Web/API/FileSystemWritableFileStream/writehttps://developer.mozilla.org/en-US/docs/Web/API/IDBMutableFile/getFile

Другие вопросы по тегам