web-dev-qa-db-fra.com

API de fichier HTML5 téléchargeant le fichier du serveur et l'enregistrant dans un bac à sable

J'essaie de comprendre l'API HTML5 ... Je conçois l'application Web dans laquelle le client du navigateur doit télécharger plusieurs fichiers à partir du serveur; utilisateur effectuera quelque chose avec les fichiers téléchargés et l'application que la nécessité de sauvegarder l'état sur l'utilisateur hard-rive. Je comprends que le navigateur peut enregistrer ces fichiers uniquement dans son sandbox, ce qui est correct tant que l'utilisateur peut récupérer ces fichiers lors du deuxième démarrage de l'application . Devrais-je utiliser BlobBuilder ou FileSaver? Je suis un peu perdu ici.

26
Mamadum

Je vais vous montrer comment télécharger des fichiers avec XMLHttpRequest Level 2 et les enregistrer avec l’API FileSystem ou avec l’interface FileSaver .

Téléchargement de fichiers

Pour télécharger un fichier, vous utiliserez XMLHttpRequest Level 2 (également appelé XHR2), qui prend en charge les requêtes inter-origines, le téléchargement d'événements de progression et le chargement/téléchargement de données binaires. Dans le post " Nouvelles astuces dans XMLHttpRequest2 ", il existe de nombreux exemples d'utilisation de XHR2.

Pour télécharger un fichier en tant que blob, il vous suffit de spécifier la variable responseType à "blob". Vous pouvez également utiliser les types "text", "arraybuffer" ou "document". La fonction ci-dessous télécharge le fichier dans la url et l'envoie au rappel success:

function downloadFile(url, success) {
    var xhr = new XMLHttpRequest(); 
    xhr.open('GET', url, true); 
    xhr.responseType = "blob";
    xhr.onreadystatechange = function () { 
        if (xhr.readyState == 4) {
            if (success) success(xhr.response);
        }
    };
    xhr.send(null);
}

Le callback success recevra en argument une instance de Blob pouvant être modifiée et sauvegardée ultérieurement et/ou téléchargée sur un serveur.

Enregistrement de fichiers avec l'API FileSystem

Comme puis-je utiliser ... site indique il n'y a pas beaucoup de navigateurs prenant en charge l'API FileSystem. Pour Firefox il y a une explication pour le manque de support. Donc, vous devrez utiliser Chrome pour le faire.

Vous devrez d’abord demander un espace de stockage, qu’il soit temporaire ou persistant. Vous voudrez probablement avoir un stockage persistant, dans ce cas, vous devrez demander un quota d’espace de stockage à l’avance ( quelques faits ):

window.requestFileSystem  = window.requestFileSystem || window.webkitRequestFileSystem;
window.storageInfo = window.storageInfo || window.webkitStorageInfo;

// Request access to the file system
var fileSystem = null         // DOMFileSystem instance
  , fsType = PERSISTENT       // PERSISTENT vs. TEMPORARY storage 
  , fsSize = 10 * 1024 * 1024 // size (bytes) of needed space 
  ;

window.storageInfo.requestQuota(fsType, fsSize, function(gb) {
    window.requestFileSystem(fsType, gb, function(fs) {
        fileSystem = fs;
    }, errorHandler);
}, errorHandler);

Maintenant que vous avez accès au système de fichiers, vous pouvez enregistrer et lire des fichiers à partir de celui-ci. La fonction ci-dessous peut enregistrer un blob dans le chemin spécifié dans le système de fichiers:

function saveFile(data, path) {
    if (!fileSystem) return;

    fileSystem.root.getFile(path, {create: true}, function(fileEntry) {
        fileEntry.createWriter(function(writer) {
            writer.write(data);
        }, errorHandler);
    }, errorHandler);
}

Un pour lire un fichier par son chemin:

function readFile(path, success) {
    fileSystem.root.getFile(path, {}, function(fileEntry) {
        fileEntry.file(function(file) {
            var reader = new FileReader();

            reader.onloadend = function(e) {
                if (success) success(this.result);
            };

            reader.readAsText(file);
        }, errorHandler);
    }, errorHandler);
}

En plus de la méthode readAsText, selon l’API FileReader vous pouvez appeler readAsArrayBuffer et readAsDataURL.

Utilisation de FileSaver

La publication " Enregistrement de fichiers générés côté client " explique très bien l’utilisation de cette API. Certains navigateurs peuvent avoir besoin de FileSaver.js pour avoir l’interface saveAs.

Si vous l'utilisez avec la fonction downloadFile, vous pourriez avoir quelque chose comme ceci:

downloadFile('image.png', function(blob) {
    saveAs(blob, "image.png");
});

Bien entendu, il serait plus logique que l’utilisateur visualise l’image, la manipule puis la sauvegarde dans son lecteur.

Gestionnaire d'erreur

Juste pour remplir l'exemple:

function errorHandler(e) {
    var msg = '';

    switch (e.code) {
        case FileError.QUOTA_EXCEEDED_ERR:
            msg = 'QUOTA_EXCEEDED_ERR';
            break;
        case FileError.NOT_FOUND_ERR:
            msg = 'NOT_FOUND_ERR';
            break;
        case FileError.SECURITY_ERR:
            msg = 'SECURITY_ERR';
            break;
        case FileError.INVALID_MODIFICATION_ERR:
            msg = 'INVALID_MODIFICATION_ERR';
            break;
        case FileError.INVALID_STATE_ERR:
            msg = 'INVALID_STATE_ERR';
            break;
        default:
            msg = 'Unknown Error';
            break;
    };

    console.log('Error: ' + msg);
}

Liens utiles

65
mayconbordin

Si vous ne prenez en charge que les navigateurs HTML5, vous pouvez utiliser un attribut "téléchargement". Plus de détails ici: http://updates.html5rocks.com/2011/08/Downloading-resources-in-HTML5-a-download

2
Trunal Bhanse

Mon astuce consiste simplement à ajouter des IFRAME avec un attribut "src" pointant vers vos téléchargements multiples. Le site du serveur doit envoyer les fichiers avec un en-tête "disposition: attachment", puis le client essaiera de stocker le fichier localement. Le seul "problème" est que les IFRAME resteront dans votre arbre DOM sous forme de débris jusqu'à ce que l'utilisateur quitte ou recharge la page. Rendez l’IFRAME invisible (par exemple, width = 0; height = 0;) et vous êtes prêt à partir! Tous les navigateurs.

0
Martin Rode