Signatur
Beschreibung
Die Methode createSyncAccessHandle() des Interfaces FileSystemFileHandle öffnet eine Datei im Origin Private File System (OPFS) für synchronen Zugriff mit hoher Leistung. Das zurückgegebene FileSystemSyncAccessHandle hat die Methoden read(), write(), truncate(), getSize(), flush() und close(). Sie arbeiten synchron und direkt auf der Datei. Dabei entsteht keine temporäre Kopie wie bei createWritable().
Die API ist für rechenintensive Fälle gedacht, bei denen viele kleine Lese- und Schreibzugriffe an beliebigen Stellen der Datei nötig sind. Typische Beispiele sind SQLite über WebAssembly, Datenbank-Engines, Video- oder Bildbearbeitung und Emulatoren. Weil synchrone Ein- und Ausgabe den Hauptthread blockieren würde, gibt es die Methode ausschließlich in dedizierten Web Workern. Im Hauptthread, in Shared Workern und in Service Workern ist sie nicht verfügbar.
Standardmäßig (mode: "readwrite") setzt die Methode eine exklusive Sperre auf die Datei. Solange das Handle offen ist, kann kein anderes Sync-Handle und kein FileSystemWritableFileStream für dieselbe Datei erzeugt werden. Deshalb muss man das Handle nach getaner Arbeit unbedingt mit close() schließen. Mit den Modi "read-only" und "readwrite-unsafe" können mehrere Handles gleichzeitig offen sein.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options | object | {} | Optionales Konfigurationsobjekt. |
| $options.mode | "readwrite" | "read-only" | "readwrite-unsafe" | "readwrite" | Sperrmodus. "readwrite": Lesen und Schreiben mit exklusiver Sperre. "read-only": nur Lesen, mehrere Handles gleichzeitig möglich, write() und truncate() werfen einen Fehler. "readwrite-unsafe": Lesen und Schreiben ohne exklusive Sperre, mehrere gleichzeitige Schreiber möglich, die Synchronisierung liegt beim Entwickler. Die Option mode gibt es derzeit nur in Chromium (ab Version 121). |
Rückgabewert
Promise, das mit einem FileSystemSyncAccessHandle für synchronen Dateizugriff erfüllt wird. Es wird abgelehnt mit NotAllowedError (Berechtigung fehlt oder die Datei liegt nicht im OPFS), InvalidStateError (das Handle gehört nicht zum OPFS), NotFoundError (die Datei existiert nicht mehr) oder NoModificationAllowedError (die Sperre ist nicht zu bekommen, weil schon ein anderes Handle offen ist).Beispiele
Text in eine OPFS-Datei schreiben und zurücklesen (worker.js)
// worker.js – läuft in einem dedizierten Web Worker
self.onmessage = async ({ data }) => {
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 bytes = encoder.encode(data);
// Datei leeren und ab Position 0 schreiben
access.truncate(0);
access.write(bytes, { at: 0 });
access.flush();
// Gesamte Datei wieder einlesen
const size = access.getSize();
const buffer = new Uint8Array(size);
access.read(buffer, { at: 0 });
self.postMessage(new TextDecoder().decode(buffer));
} finally {
access.close(); // Sperre unbedingt freigeben!
}
};
Worker aus dem Hauptthread starten
// main.js
const worker = new Worker('worker.js');
worker.onmessage = ({ data }) => {
console.log('Vom Worker gelesen:', data);
};
worker.postMessage('Hallo OPFS!');
Daten an die Datei anhängen (Log-Datei)
// worker.js
const appendLog = async (line) => {
const root = await navigator.storage.getDirectory();
const handle = await root.getFileHandle('app.log', { create: true });
const access = await handle.createSyncAccessHandle();
try {
const bytes = new TextEncoder().encode(`${new Date().toISOString()} ${line}\n`);
// Am aktuellen Dateiende anhängen
const written = access.write(bytes, { at: access.getSize() });
access.flush();
return written;
} finally {
access.close();
}
};
appendLog('Worker gestartet').then((n) => console.log(`${n} Bytes geschrieben`));
Mehrere gleichzeitige Leser mit mode: "read-only" (Chromium)
// worker.js – Chromium 121+
const root = await navigator.storage.getDirectory();
const handle = await root.getFileHandle('daten.bin', { create: true });
// Ohne mode würde der zweite Aufruf mit NoModificationAllowedError fehlschlagen
const readerA = await handle.createSyncAccessHandle({ mode: 'read-only' });
const readerB = await handle.createSyncAccessHandle({ mode: 'read-only' });
console.log(readerA.getSize() === readerB.getSize());
readerA.close();
readerB.close();
// Wichtig · Fallstricke
- Nur in dedizierten Workern: Im Hauptthread ist
createSyncAccessHandleundefined. Vorher mit'createSyncAccessHandle' in FileSystemFileHandle.prototypeprüfen. - Nur OPFS: Die Methode funktioniert nur mit Handles aus
navigator.storage.getDirectory(). Bei Dateien, die pershowOpenFilePicker()gewählt wurden, wird das Promise abgelehnt. - Exklusive Sperre: Im Standardmodus blockiert ein offenes Handle alle weiteren Zugriffe auf die Datei, auch aus anderen Tabs. Deshalb immer
close()in einemfinally-Block aufrufen, sonst bleibt die Datei bis zum Beenden des Workers gesperrt. - Ältere Safari-Versionen (vor 16.4) haben
getSize(),truncate(),flush()undclose()asynchron umgesetzt, also mit Promise als Rückgabewert. Für breite Kompatibilität kann man deren Ergebnis mitawaitabwarten. Bei synchronen Rückgabewerten schadet das nicht. - Die Option
modegibt es derzeit nur in Chromium (ab 121). Firefox und Safari ignorieren sie und verwenden immer"readwrite". read()undwrite()erwarten einArrayBuffer, eineTypedArrayoder eineDataView. Strings muss man vorher mitTextEncoderumwandeln.- Das OPFS unterliegt der Speicherquote des Browsers. Nutzer können die Daten beim Löschen der Website-Daten entfernen. Mit
navigator.storage.persist()lässt sich dauerhafter Speicher anfordern.