Zum Hauptinhalt springen

Capacitor File-Handling-Guide: Lesen, Schreiben, Auswählen, Teilen

Capacitor Guide zum Dateimanagement: Dateien lesen und schreiben, Verzeichnisse wählen, Dateien auswählen, anzeigen, öffnen, teilen, herunterladen und hochladen auf iOS und Android.

Dateien lesen, schreiben und teilen in einer Capacitor Mobile App

Das Capacitor File Handling basiert auf wenigen Bausteinen: @capacitor/filesystem um Dateien in App-Verzeichnissen zu lesen und zu schreiben, Capacitor.convertFileSrc um sie anzuzeigen, einen Picker zum Importieren von Nutzerdateien sowie native Plugins zum Download, Upload, Öffnen und Teilen. Dieser Guide zeigt jedes Tool mit Capacitor 8 code, erklärt die Verzeichnisse unter iOS und Android und deckt Memory- sowie Permission-Fallen ab, die die meisten File-Bugs verursachen.

Das File-Handling-Toolkit

Aufgabe Plugin
Lesen, Schreiben, Auflisten, Kopieren, Löschen im App-Speicher @capacitor/filesystem
Lokale Datei anzeigen in <img>, <video>, <iframe> Capacitor.convertFileSrc (Core)
Dateien oder Ordner auswählen lassen @capgo/capacitor-file-picker
Download mit Fortschrittsanzeige @capacitor/file-transfer oder @capgo/capacitor-downloader für Hintergrund-Downloads (pausierbar)
Upload mit Fortschrittsanzeige @capacitor/file-transfer oder @capgo/capacitor-uploader für Hintergrund-Uploads
Datei teilen oder in Downloads speichern @capgo/capacitor-file-sharer oder @capacitor/share
Datei in einer anderen App öffnen @capacitor-community/file-opener
Bilder komprimieren @capgo/capacitor-file-compressor
Zippen und Entpacken @capgo/capacitor-zip

Installiere zuerst das Core-Plugin:

bun add @capacitor/filesystem
bunx cap sync

Das richtige Verzeichnis wählen

Jeder Filesystem-Aufruf benötigt einen directory. Die falsche Wahl ist die häufigste Ursache für verlorene Dateien und App-Ablehnungen.

Directory iOS-Speicherort Android-Speicherort Gesichert Verwenden für
Data Documents App-Dateiverzeichnis (/data/data/<pkg>/files) iOS iCloud, Android Auto Backup Benutzerdaten, die die App verwaltet
Documents Documents (wie bei Data) Öffentlich Documents Ordner Ja Ab Android 11+ vermeiden, siehe unten
Library Library App-Dateiverzeichnis iOS: ja App-Supportdateien, Datenbanken
LibraryNoCloud Library/NoCloud App-Dateiverzeichnis Nein Große, erneut ladbare Inhalte
Cache Library/Caches App-Cache-Verzeichnis Nein Temporäre Dateien, können vom OS gelöscht werden
External Documents Externer App-Dateipfad Nein Große App-Dateien auf Android, Löschung bei Deinstallation
ExternalStorage Documents Root des Shared Storage k. A. Nur Legacy, nicht zugänglich ab Android 11+

Faustregeln:

  • Große, erneut ladbare Medien (Offline-Videos, Map Tiles) werden hier gespeichert LibraryNoCloud. Apple lehnt Apps ab, die große, erneut ladbare Inhalte in iCloud-gestützten Ordnern speichern, wie in den iOS Data Storage Guidelines beschrieben.
  • Temporäre Dateien (Exports, die du einmalig teilst, z. B. Thumbnails) kommen in Cache. Speichere dort niemals die einzige Kopie von Nutzerdaten.
  • Dateien, die Nutzer später außerhalb deiner App finden sollen, gehören gar nicht in ein App-Verzeichnis. Speichere sie über das Share Sheet, MediaStore Downloads oder den System-File-Picker. Siehe unseren Guide zu Android Scoped Storage in Capacitor.

Eine Datei schreiben

import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';

// Text file
await Filesystem.writeFile({
  path: 'notes/today.txt',
  data: 'Hello from Capacitor',
  directory: Directory.Data,
  encoding: Encoding.UTF8,
  recursive: true, // create notes/ if missing
});

// JSON
await Filesystem.writeFile({
  path: 'settings.json',
  data: JSON.stringify({ theme: 'dark' }),
  directory: Directory.Data,
  encoding: Encoding.UTF8,
});

// Binary file: pass base64 and no encoding
await Filesystem.writeFile({
  path: 'images/logo.png',
  data: base64Png,
  directory: Directory.Data,
  recursive: true,
});

Der encoding Option entscheidet darüber, wie data interpretiert wird. Mit Encoding.UTF8wird der String als Text geschrieben. Ohne sie dekodieren native Plattformen data als Base64 und schreiben die Rohdaten. Das ist der klassische „Mein PDF ist korrupt“-Bug.

Um eine bestehende Datei, wie etwa ein Log, zu ergänzen, nutze appendFile mit denselben Optionen.

Eine Datei lesen

const { data } = await Filesystem.readFile({
  path: 'settings.json',
  directory: Directory.Data,
  encoding: Encoding.UTF8,
});
const settings = JSON.parse(data as string);

// Binary: returns base64 on native, a Blob on web
const image = await Filesystem.readFile({
  path: 'images/logo.png',
  directory: Directory.Data,
});

Prüfen, ob eine Datei existiert, mit stat, was fehlschlägt, wenn die Datei fehlt:

async function exists(path: string) {
  try {
    await Filesystem.stat({ path, directory: Directory.Data });
    return true;
  } catch {
    return false;
  }
}

Große Dateien in Chunks lesen

readFile gibt die gesamte Datei als einen einzigen Base64-String zurück. Bei einem 200-MB-Video bedeutet das hunderte MB an Strings im JS-Speicher. readFileInChunks nutzt stattdessen Streaming:

await Filesystem.readFileInChunks(
  { path: 'videos/clip.mp4', directory: Directory.Data, chunkSize: 1024 * 1024 },
  (chunk, err) => {
    if (err) return console.error(err);
    if (chunk === null) return console.log('done');
    processChunk(chunk.data); // base64 chunk
  },
);

Noch besser: Vermeide es ganz, die Bytes durch JS zu schleusen. Die meisten „große Datei lesen“-Tasks sind eigentlich „hochladen“ oder „anzeigen“ – beides hat unten native Wege.

Auflisten, kopieren, verschieben und löschen

const { files } = await Filesystem.readdir({ path: 'notes', directory: Directory.Data });
for (const f of files) console.log(f.name, f.type, f.size, f.mtime);

await Filesystem.mkdir({ path: 'archive', directory: Directory.Data, recursive: true });

await Filesystem.copy({
  from: 'notes/today.txt',
  to: 'archive/today.txt',
  directory: Directory.Data,
});

await Filesystem.rename({
  from: 'archive/today.txt',
  to: 'archive/2026-10-01.txt',
  directory: Directory.Data,
});

await Filesystem.deleteFile({ path: 'notes/today.txt', directory: Directory.Data });
await Filesystem.rmdir({ path: 'notes', directory: Directory.Data, recursive: true });

copy und rename akzeptieren toDirectory um zwischen Verzeichnissen zu wechseln, zum Beispiel von Cache zu Data nach einem abgeschlossenen Download. Sie akzeptieren auch absolute file:// Pfade, wenn du directoryauslässt, so wie man Dateien importiert, die von anderen Plugins zurückgegeben werden.

Eine Datei in der WebView anzeigen

Vermeide es nach Möglichkeit, Bilder oder Videos als base64-Data-URLs zu laden. Wandle stattdessen den nativen Pfad in eine URL um, die vom lokalen Server von Capacitor bereitgestellt wird:

import { Capacitor } from '@capacitor/core';

const { uri } = await Filesystem.getUri({ path: 'images/logo.png', directory: Directory.Data });
img.src = Capacitor.convertFileSrc(uri);

Unter iOS sieht das Ergebnis so aus: capacitor://localhost/_capacitor_file_/..., unter Android: https://localhost/_capacitor_file_/.... Das funktioniert für <img>, <video>, <audio>, und fetch(), was bedeutet, dass du eine Datei auch als ArrayBuffer ohne base64 lesen kannst:

const buffer = await fetch(Capacitor.convertFileSrc(uri)).then((r) => r.arrayBuffer());

Speichere Pfade, keine umgewandelten URLs. Die umgewandelte Form ist nur für die aktuelle App-Session gültig.

Dateien vom Gerät auswählen

Der System-Picker gibt dem Nutzer die Kontrolle und braucht unter Android 13+ oder iOS keine Speicherberechtigung:

bun add @capgo/capacitor-file-picker
bunx cap sync
import { CapgoFilePicker } from '@capgo/capacitor-file-picker';

const { files } = await CapgoFilePicker.pickFiles({
  types: ['application/pdf', 'image/*'],
  limit: 5,
  readData: false, // keep false for anything bigger than a few MB
});

for (const file of files) {
  console.log(file.name, file.mimeType, file.size, file.path);
}

Es gibt auch pickImages, pickVideos, pickMedia und pickDirectory, plus convertHeicToJpeg unter iOS. Unter iOS types akzeptiert nur MIME-Typen, keine Dateiendungen.

Ausgewählte Dateien können an einem temporären Ort liegen oder hinter einer content:// Eine URI, die nur vorübergehend lesbar bleibt. Wenn du die Datei später noch benötigst, kopiere sie am besten sofort mit Filesystem.copy.

Dateien downloaden

Mit Fortschrittsanzeige: @capacitor/file-transfer

Filesystem.downloadFile ist in Filesystem 8 veraltet. Die Alternative streamt die Antwort direkt auf die Festplatte:

bun add @capacitor/file-transfer
bunx cap sync
import { FileTransfer } from '@capacitor/file-transfer';
import { Directory, Filesystem } from '@capacitor/filesystem';

const { uri } = await Filesystem.getUri({ path: 'downloads/report.pdf', directory: Directory.Data });

const listener = await FileTransfer.addListener('progress', (p) => {
  if (p.lengthComputable) setProgress(p.bytes / p.contentLength);
});

await FileTransfer.downloadFile({
  url: 'https://example.com/report.pdf',
  path: uri,
  progress: true,
  headers: { Authorization: `Bearer ${token}` },
});

await listener.remove();

Im Hintergrund: @capgo/capacitor-downloader

Für große Dateien, die auch beim Verlassen der App weitergeladen werden sollen und die pausiert sowie fortgesetzt werden können, nutze den Capgo Downloader, der auf DownloadManager auf Android und im Hintergrund URLSession auf iOS:

import { CapacitorDownloader } from '@capgo/capacitor-downloader';

await CapacitorDownloader.addListener('downloadProgress', ({ id, progress }) => {
  console.log(id, progress);
});
await CapacitorDownloader.addListener('downloadCompleted', ({ id }) => {
  console.log('done', id);
});

await CapacitorDownloader.download({
  id: 'course-video-12',
  url: 'https://cdn.example.com/course/12.mp4',
  destination: 'videos/12.mp4',
  network: 'wifi-only',
  notification: 'progress', // Android
});

Ein relativer destination entspricht dem externen Files-Verzeichnis der App auf Android und dem Documents Verzeichnis auf iOS, also denselben Orten wie Directory.External.

Dateien hochladen

Lies eine Datei nicht erst in base64, nur um sie zu senden. Beide Upload-Optionen lesen nativ von der Festplatte:

import { FileTransfer } from '@capacitor/file-transfer';

const result = await FileTransfer.uploadFile({
  url: 'https://api.example.com/upload',
  path: uri,          // full file:// path
  fileKey: 'file',
  mimeType: 'application/pdf',
  headers: { Authorization: `Bearer ${token}` },
  progress: true,
});
console.log(result.responseCode, result.bytesSent);

Für Uploads, die auch im Hintergrund der App fortgesetzt werden müssen (Videos, Batch-Foto-Uploads), nutze @capgo/capacitor-uploader, das in einem Hintergrundprozess läuft URLSession auf iOS und ein Upload-Service mit Fortschrittsanzeige auf Android:

import { Uploader } from '@capgo/capacitor-uploader';

const { id } = await Uploader.startUpload({
  filePath: uri,
  serverUrl: 'https://api.example.com/upload',
  method: 'PUT', // binary body, ideal for presigned S3 or R2 URLs
  mimeType: 'video/mp4',
});

Presigned PUT URLs für Object Storage sind das zuverlässigste Muster für große Dateien: Dein API signiert die URL und das Gerät lädt direkt in den Storage hoch.

Datei teilen oder exportieren

Damit Nutzer eine Datei an eine andere App senden oder an einem Ort speichern können, an dem sie sie wiederfinden:

import { FileSharer } from '@capgo/capacitor-file-sharer';

await FileSharer.share({
  filename: 'report.pdf',
  path: uri,
  contentType: 'application/pdf',
});

// Android: write to Downloads via MediaStore. iOS: opens the share sheet ("Save to Files")
await FileSharer.save({
  filename: 'report.pdf',
  path: uri,
  contentType: 'application/pdf',
});

Der Capgo File-Sharer kopiert die Datei in seinen eigenen Cache-Ordner und stellt sie über einen speziellen FileProvider, sodass du nichts bearbeiten musst file_paths.xml. Mit dem offiziellen @capacitor/share, kann Android nur aus dem Cache-Ordner heraus teilen, es sei denn, du fügst weitere Ordner hinzu android/app/src/main/res/xml/file_paths.xml.

Datei in einer anderen App öffnen

bun add @capacitor-community/file-opener
bunx cap sync
import { FileOpener } from '@capacitor-community/file-opener';

await FileOpener.open({ filePath: uri, contentType: 'application/pdf' });

Unter iOS öffnet dies eine Quick Look-Vorschau. Unter Android wird die Standard-App für den MIME-Typ geöffnet oder ein Chooser angezeigt. Wenn keine App den Typ verarbeiten kann, schlägt der Aufruf fehl; fange diesen Fehler ab und biete stattdessen das Teilen an.

Gängige Datei-Rezepte

Ein PDF generieren: HTML rendern mit @capgo/capacitor-pdf-generator oder es in JS bauen mit pdf-lib, und dann den Base64-Output mit writeFile. Unsere Scan-to-PDF-Tutorial zeigt den kompletten Workflow.

GPS-Daten vor dem Upload aus einem Foto entfernen: @capgo/capacitor-file-compressor entfernt auf jeder Plattform die EXIF-Metadaten beim Resizing.

Ein Bild skalieren oder konvertieren: derselbe Compressor übernimmt Breite, Höhe, Qualität und das Ausgabeformat, inklusive HEIC zu JPEG.

Viele Dateien bündeln: einen Ordner mit ... zippen @capgo/capacitor-zip und statt hunderter Requests nur ein Archiv hochladen.

Web-Support

@capacitor/filesystem funktioniert im Web via IndexedDB, sodass dein code während der Entwicklung im Browser läuft. Unterschiede, die du beachten solltest: Binary-Reads geben einen Blobzurück, Dateien liegen nur im Browser-Profil und die Speicherlimits sind deutlich niedriger. Für Web-Builds empfiehlt sich URL.createObjectURL(blob) zur Anzeige.

Fehlerbehebung

„Datei existiert nicht“: Verwechslung der Verzeichnisse oder ein absoluter Pfad zusammen mit einem directory. Nutze nur eines von beiden.

Beschädigte Binärdateien: du hast Base64 mit Encoding.UTF8. Entferne die Kodierung.

App stürzt bei großen Dateien ab: base64 über die Bridge. Nutze Chunks, File-Transfer oder fetch(convertFileSrc(uri)).

Bild wird auf Android nicht angezeigt: du hast einen file:// URL direkt. Konvertiere sie mit Capacitor.convertFileSrc.

Failed to find configured root beim Teilen unter Android: die Datei liegt außerhalb der Pfade in file_paths.xml. Nutze den Capgo File Sharer oder kopiere nach Cache zuerst.

Dateien verschwinden unter iOS: sie lagen in Cache, was iOS bei Speicherplatzmangel bereinigt.

Ablehnung im App Store wegen iCloud-Speicher: große Download-Inhalte in Data oder Documents. Verschiebe sie nach LibraryNoCloud.

Nächste Schritte

Die meiste Dateilogik, wie Speicherorte, Retry-Regeln und Benennungen, liegt in JavaScript und lässt sich mit Capgo Live Updates nach dem Release anpassen. Für die Android-Seite bezüglich Shared Storage und Berechtigungen nutze unseren Scoped Storage Guide, und schau dir die File Picker Docs an für jede Picker-Option.

Live-Updates für Capacitor-Apps

Wenn ein Bug im Web-Layer live ist, liefere den Fix über Capgo aus, statt Tage auf die App-Store-Freigabe zu warten. Nutzer bekommen das Update im Hintergrund, während native Änderungen im normalen Review-Prozess bleiben.

Neues aus unserem Blog

Capgo gibt dir die besten Insights, um eine wirklich professionelle Mobile App zu erstellen.