是否可以使用 Chrome 的文件系统访问 API 附加到现有文件



使用新的File System Access API可以读取和写入用户设备上的文件和文件夹:

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

上面的代码将写";Hello World"到所选文件。如果该文件已经存在,它将被截断并被新内容覆盖。

是否可以在不读取整个文件并再次写入的情况下附加到现有文件?一个很好的例子可以是写入日志文件。

Joe Duncan是正确的(谢谢你的提示!(

但您需要以"追加"模式打开可写文件。

我需要在写完每一行后关闭/刷新文件,然后重新打开、查找并附加到该文件(但只需单击1次SaveFile按钮(

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

最新更新