Signatur
Beschreibung
FileSystemSyncAccessHandle gehört zur File System API und bietet synchronen, sehr performanten Zugriff auf eine einzelne Datei im Origin Private File System (OPFS). Das OPFS ist ein privater Speicherbereich pro Origin. Der Nutzer sieht ihn nicht, und es gibt keine Berechtigungsdialoge. Einen Handle bekommst du nur über FileSystemFileHandle.createSyncAccessHandle(). Diese Methode steht ausschließlich in dedizierten Web Workern zur Verfügung, damit synchrone Ein- und Ausgaben nie den Haupt-Thread blockieren.
Die Schnittstelle ist für Anwendungen gedacht, die viele kleine Lese- und Schreibzugriffe an beliebigen Stellen einer Datei brauchen. Typische Beispiele sind Datenbanken, die nach WebAssembly übersetzt wurden (etwa SQLite-Wasm), Emulatoren, Spiele-Engines oder Editoren für große Binärdateien. Anders als FileSystemWritableFileStream schreibst du direkt in die Datei. Es gibt keine temporäre Kopie und keinen Tausch der Datei beim Schließen.
Die Methoden im Überblick:
read(buffer, { at }): liest Bytes in einenArrayBufferbzw. eineArrayBufferViewund gibt die Anzahl gelesener Bytes zurück.write(buffer, { at }): schreibt Bytes aus einem Puffer in die Datei und gibt die Anzahl geschriebener Bytes zurück.getSize(): gibt die aktuelle Dateigröße in Bytes zurück.truncate(newSize): kürzt die Datei aufnewSizeBytes oder verlängert sie auf diese Größe.flush(): sorgt dafür, dass alle Änderungen auf dem Datenträger gespeichert werden.close(): schließt den Handle und gibt die exklusive Sperre auf die Datei frei.
Solange ein Sync-Access-Handle geöffnet ist, hält er standardmäßig eine exklusive Sperre auf die Datei. Andere Handles (auch in anderen Tabs) können die Datei erst öffnen, wenn du close() aufgerufen hast.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $buffer Pflicht | ArrayBuffer | ArrayBufferView | Für read() der Zielpuffer, für write() der Quellpuffer mit den Bytes. |
|
| $options.at | number | Aktuelle Position des Dateizeigers | Byte-Offset in der Datei, ab dem read() bzw. write() arbeitet. |
| $newSize Pflicht | number | Neue Dateigröße in Bytes für truncate(). |
Rückgabewert
await fileHandle.createSyncAccessHandle(). read(), write() und getSize() geben eine number zurück, truncate(), flush() und close() geben undefined zurück. In aktuellen Browsern arbeiten alle diese Methoden synchron.Beispiele
Handle im Worker erzeugen, Text schreiben und wieder lesen
// worker.js – läuft in einem dedizierten Web Worker
const run = async () => {
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('notizen.txt', { create: true });
const access = await fileHandle.createSyncAccessHandle();
try {
const encoder = new TextEncoder();
const decoder = new TextDecoder();
// Datei leeren und neu beschreiben
access.truncate(0);
const written = access.write(encoder.encode('Hallo OPFS!'), { at: 0 });
access.flush();
// Gesamten Inhalt zurücklesen
const size = access.getSize();
const buffer = new Uint8Array(size);
access.read(buffer, { at: 0 });
postMessage({ written, size, text: decoder.decode(buffer) });
} finally {
access.close(); // Sperre freigeben
}
};
run();
Daten an eine Protokolldatei anhängen
// worker.js
const appendLog = async (line) => {
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('app.log', { create: true });
const access = await fileHandle.createSyncAccessHandle();
try {
const bytes = new TextEncoder().encode(`${new Date().toISOString()} ${line}\n`);
// Ans Dateiende schreiben
access.write(bytes, { at: access.getSize() });
access.flush();
return access.getSize();
} finally {
access.close();
}
};
self.onmessage = async (event) => {
const newSize = await appendLog(event.data);
postMessage(`Log-Größe: ${newSize} Bytes`);
};
Wahlfreier Zugriff: Datensätze fester Länge lesen und ändern
// worker.js – einfache "Datenbank" mit 8-Byte-Datensätzen (Float64)
const RECORD = 8;
const main = async () => {
const root = await navigator.storage.getDirectory();
const fh = await root.getFileHandle('werte.bin', { create: true });
const access = await fh.createSyncAccessHandle();
try {
// Platz für 100 Datensätze reservieren
access.truncate(100 * RECORD);
// Datensatz Nr. 42 schreiben
const out = new Float64Array([3.14159]);
access.write(out, { at: 42 * RECORD });
// Datensatz Nr. 42 wieder lesen
const inBuf = new Float64Array(1);
access.read(inBuf, { at: 42 * RECORD });
console.log(inBuf[0], access.getSize());
} finally {
access.close();
}
};
main();
// Wichtig · Fallstricke
- Nur in dedizierten Workern:
createSyncAccessHandle()gibt es weder im Haupt-Thread noch in Shared Workern oder Service Workern. Im Fenster-Kontext ist die Methode nicht definiert. - Nur im OPFS: Für Dateien, die der Nutzer über
showOpenFilePicker()ausgewählt hat, funktioniert die Methode nicht. Sie ist nur für Handles ausnavigator.storage.getDirectory()verfügbar. - Exklusive Sperre: Ein offener Handle sperrt die Datei. Ein zweiter Aufruf von
createSyncAccessHandle()wirft dann eineNoModificationAllowedError. Rufeclose()deshalb immer auf, am besten in einemfinally-Block. Chrome kennt zusätzlich die Option{ mode: 'readwrite-unsafe' }bzw.'read-only', damit mehrere Handles gleichzeitig auf eine Datei zugreifen können. Andere Browser unterstützen diese Option noch nicht überall. - Historische Asynchronität: In frühen Chrome-Versionen (bis 107) gaben
getSize(),truncate(),flush()undclose()ein Promise zurück. Falls du ältere Browser unterstützen musst, schreibeawaitdavor. Bei synchronen Rückgabewerten schadet das nicht. - Offset angeben: Ohne
atarbeitenread()undwrite()ab einem internen Dateizeiger, der nach jedem Aufruf weiterwandert. Das führt leicht zu Fehlern. Gib den Offset deshalb besser immer ausdrücklich an. - Speicherkontingent: Geht beim Schreiben der Speicherplatz aus, wird eine
QuotaExceededErrorgeworfen. Wie viel Platz noch frei ist, erfährst du mitnavigator.storage.estimate(). - Die Daten im OPFS können gelöscht werden, wenn der Browser Speicher freigibt. Mit
navigator.storage.persist()kannst du beantragen, dass sie dauerhaft erhalten bleiben.