Aller au contenu principal

Capacitor Guide de gestion de fichiers : lire, écrire, choisir, partager

Guide de gestion des fichiers Capacitor : lire et écrire des fichiers, choisir des répertoires, sélectionner, afficher, ouvrir, partager, télécharger et envoyer des fichiers sur iOS et Android.

Lecture, écriture et partage de fichiers dans une application mobile Capacitor

La gestion des fichiers dans Capacitor repose sur quelques briques de base : @capacitor/filesystem pour lire et écrire des fichiers dans les répertoires de l’app, Capacitor.convertFileSrc pour les afficher, un sélecteur pour importer des fichiers de l’utilisateur, et des plugins natifs pour télécharger, envoyer, ouvrir et partager. Ce guide présente chacun d’eux avec Capacitor 8 code, explique quel répertoire utiliser sur iOS et Android, et aborde les pièges de mémoire et d’autorisations à l’origine de la plupart des bugs de fichiers.

La boîte à outils de la gestion de fichiers

Tâche Plugin
Lire, écrire, lister, copier et supprimer dans le stockage de l’app @capacitor/filesystem
Afficher un fichier local dans <img>, <video>, <iframe> Capacitor.convertFileSrc (noyau)
Let the user pick files or a folder @capgo/capacitor-file-picker
Télécharger avec progression @capacitor/file-transfer ou @capgo/capacitor-downloader for background, pausable downloads
Envoyer avec progression @capacitor/file-transfer ou @capgo/capacitor-uploader pour les uploads en arrière-plan
Share a file or save it to Downloads @capgo/capacitor-file-sharer ou @capacitor/share
Ouvrir un fichier dans une autre application @capacitor-community/file-opener
Compresser des images @capgo/capacitor-file-compressor
Zipper et dézipper @capgo/capacitor-zip

Installez d’abord le plugin principal :

bun add @capacitor/filesystem
bunx cap sync

Choisir le bon répertoire

Chaque appel à Filesystem prend un directory. Choisir le mauvais répertoire est la cause la plus fréquente de fichiers perdus et d’applications rejetées.

Directory Emplacement iOS Emplacement Android Sauvegardé À utiliser pour
Data Documents Répertoire des fichiers de l’app (/data/data/<pkg>/files) iCloud iOS, Auto Backup Android Données utilisateur propres à l’app
Documents Documents (identique à Data) Public Documents dossier Oui À éviter sur Android 11+, voir ci-dessous
Library Library Répertoire des fichiers de l’app Oui sur iOS Fichiers de support de l’app, bases de données
LibraryNoCloud Library/NoCloud Répertoire des fichiers de l’app Non Contenu volumineux, téléchargeable à nouveau
Cache Library/Caches Répertoire de cache de l’app Non Temporary files, can be wiped by the OS
External Documents Répertoire de fichiers externes de l’app Non Grands fichiers de l’app sur Android, supprimés à la désinstallation
ExternalStorage Documents Racine du stockage partagé n/a Legacy uniquement, inaccessible sur Android 11+

Règles empiriques :

  • Médias volumineux re-téléchargeables (vidéos hors ligne, tuiles de cartes) vont ici LibraryNoCloud. Apple rejette les apps qui placent du contenu volumineux re-téléchargeable dans des dossiers sauvegardés par iCloud, comme décrit dans ses iOS Data Storage Guidelines.
  • Fichiers temporaires (exports que vous partagez une fois, vignettes) vont dans Cache. Ne stockez jamais la seule copie des données utilisateur là-bas.
  • Files the user should find later outside your app n'appartiennent pas du tout à un répertoire d'application. Enregistrez-les via la feuille de partage, MediaStore Downloads ou le sélecteur de fichiers système. Consultez notre guide sur le stockage scopé Android dans Capacitor.

Écrire un fichier

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,
});

Le encoding l'option décide comment data est interprété. Avec Encoding.UTF8, la chaîne est écrite en texte. Sans elle, les plateformes natives décodent data en base64 et écrivent des octets bruts. Oublier ce point est le bug classique « mon PDF est corrompu ».

Pour ajouter à un fichier existant, comme un log, utilisez appendFile avec les mêmes options.

Lire un fichier

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,
});

Vérifiez si un fichier existe avec stat, qui rejette la promesse si le fichier est manquant :

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

Lire de gros fichiers par blocs

readFile retourne le fichier entier sous forme d'une seule chaîne base64. Pour une vidéo de 200 Mo, cela représente des centaines de Mo de chaînes en mémoire JS. readFileInChunks il les transmet en 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
  },
);

Mieux encore, évitez de faire transiter les octets par JS. La plupart des tâches de « lecture d'un gros fichier » sont en réalité des « uploads » ou des « affichages », et les deux disposent de chemins natifs ci-dessous.

Lister, copier, déplacer et supprimer

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 et rename d'accepter toDirectory pour passer d'un répertoire à l'autre, par exemple de Cache vers Data après la fin d’un téléchargement. Ils acceptent également des chemins absolus file:// lorsque vous omettez directory, ce qui est la méthode pour importer des fichiers renvoyés par d’autres plugins.

Afficher un fichier dans la WebView

Évitez autant que possible de charger des images ou des vidéos sous forme d'URL de données base64. Convertissez le chemin natif en une URL servie par le serveur local de Capacitor :

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

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

Sur iOS, le résultat ressemble à ceci : capacitor://localhost/_capacitor_file_/..., sur Android : https://localhost/_capacitor_file_/.... Cela fonctionne pour <img>, <video>, <audio>, et fetch(), ce qui signifie que vous pouvez également lire un fichier en ArrayBuffer sans base64 :

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

Stockez les chemins, pas les URL converties. La forme convertie n'est valide que pour la session actuelle de l'application.

Sélectionner des fichiers sur l'appareil

Le sélecteur système donne le contrôl’à l'utilisateur et ne nécessite aucune permission de stockage sur Android 13+ ou iOS :

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);
}

Il existe également pickImages, pickVideos, pickMedia et pickDirectory, ainsi que convertHeicToJpeg sur iOS. Sur iOS, types n’accepte que les types MIME, pas les extensions.

Picked files may live in a temporary location or behind a content:// URI qui ne reste lisible que pendant un certain temps. Si vous avez besoin du fichier plus tard, copiez-l’immédiatement dans votre propre répertoire avec Filesystem.copy.

Télécharger des fichiers

Avec la progression : @capacitor/file-transfer

Filesystem.downloadFile est déprécié dans Filesystem 8. Le remplacement envoie le flux de la réponse directement sur le disque :

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();

En arrière-plan : @capgo/capacitor-downloader

Pour les gros fichiers qui doivent continuer à se télécharger quand l'utilisateur quitte l'app, et qui peuvent être mis en pause et repris, utilisez le téléchargeur Capgo, qui s'appuie sur DownloadManager sur Android et en arrière-plan URLSession sur 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
});

Un chemin relatif destination résout vers le répertoire de fichiers externes de l'app sur Android et le Documents répertoire sur iOS, les mêmes emplacements que Directory.External.

Envoyer des fichiers

Ne lisez pas un fichier en base64 juste pour l'envoyer. Les deux options d'upload lisent nativement depuis le disque :

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);

Pour les uploads qui doivent survivre à la mise en arrière-plan de l’app (vidéos, envoi de photos en lot), utilisez @capgo/capacitor-uploader, qui s'exécute en arrière-plan URLSession sur iOS et un service d’upload avec une notification de progression sur 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',
});

Pré-signées PUT Les URLs pré-signées vers le stockage objet sont le modèle le plus fiable pour les gros fichiers : votre API signe l’URL, et l’appareil envoie directement le fichier au stockage.

Partager ou exporter un fichier

To let the user send a file to another app or save it where they can find it:

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',
});

Le plugin de partage de fichiers Capgo copie le fichier dans son propre dossier de cache et le sert via un FileProvider dédié, vous n'avez donc pas besoin de modifier file_paths.xml. With the official @capacitor/shareofficiel, Android ne peut partager que depuis le dossier de cache, à moins d'ajouter d'autres dossiers à android/app/src/main/res/xml/file_paths.xml.

Ouvrir un fichier dans une autre application

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

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

Sur iOS, cela ouvre un aperçu Quick Look. Sur Android, cela ouvre l'application par défaut pour le type MIME ou affiche un sélecteur. Si aucune application ne peut gérer le type, l'appel est rejeté : interceptez l'erreur et proposez plutôt le partage.

Recettes courantes pour les fichiers

Générer un PDF: rendez le HTML avec @capgo/capacitor-pdf-generator ou créez-l’en JS avec pdf-lib, puis écrivez la sortie base64 avec writeFile. Notre tutoriel : scanner vers PDF présente le flux complet.

Supprimer les GPS d’une photo avant l’upload: @capgo/capacitor-file-compressor removes EXIF metadata on every platform while resizing.

Redimensionner ou convertir une image: le même compresseur gère la largeur, la hauteur, la qualité et le format de sortie, y compris HEIC vers JPEG.

Regrouper plusieurs fichiers: compresser un dossier en @capgo/capacitor-zip et envoyer une seule archive au lieu de centaines de requêtes.

Support web

@capacitor/filesystem fonctionne sur le web via IndexedDB, votre code s’exécute donc dans le navigateur pendant le développement. Différences à garder en tête : les lectures binaires renvoient un Blob, les fichiers ne vivent que dans le profil du navigateur et les quotas de stockage sont bien plus faibles. Pour les builds web, privilégiez URL.createObjectURL(blob) pour l'affichage.

Troubleshooting

« File does not exist » : vous avez mélangé les répertoires, ou passé un chemin absolu avec un directory. Utilisez l'un ou l'autre.

Fichiers binaires corrompus : vous avez écrit du base64 avec Encoding.UTF8. Supprimez l'encodage.

L'app crash avec des fichiers volumineux : base64 via le bridge. Utilisez des chunks, le file-transfer, ou fetch(convertFileSrc(uri)).

L'image ne s'affiche pas sur Android : vous avez utilisé un file:// URL directement. Convertissez-l’avec Capacitor.convertFileSrc.

Failed to find configured root lors du partage sur Android: le fichier se trouve en dehors des chemins file_paths.xml. Utilisez le Capgo file sharer ou copiez Cache d'abord.

Les fichiers disparaissent sur iOS: ils se trouvaient dans Cache, que iOS supprime en cas de pression sur le stockage.

Rejet par l’App Store pour stockage iCloud: contenu téléchargeable volumineux dans Data ou Documents. Déplacez-le dans LibraryNoCloud.

Prochaines étapes

La plupart de la logique de fichiers, comme l’emplacement de stockage, les règles de réessai et la nomenclature, est gérée en JavaScript et peut être ajustée avec les live updates Capgo après la release. Pour la partie Android du stockage partagé et des autorisations, poursuivez avec notre guide sur le scoped storage, et consultez la documentation du sélecteur de fichiers pour chaque option du sélecteur.

Live updates pour les apps Capacitor

Lorsqu'un bug de la couche web est en ligne, déployez le correctif via Capgo au lieu d'attendre des jours l'approbation des stores. Les utilisateurs reçoivent la mise à jour en arrière-plan, tandis que les changements natifs suivent le circuit de validation habituel.

Les derniers articles du blog

Capgo vous offre les meilleures informations pour créer une application mobile vraiment professionnelle.