web-dev-qa-db-fra.com

Utilisation de HTML5 / JavaScript pour générer et enregistrer un fichier

Je me suis mis à jouer à WebGL ces derniers temps et je travaille avec un lecteur Collada. Le problème est que c'est assez lent (Collada est un format très prolixe), je vais donc commencer à convertir les fichiers en un format plus facile à utiliser (probablement JSON). J'ai déjà le code pour analyser le fichier en JavaScript, je peux donc aussi bien l'utiliser comme exportateur! Le problème est économiser.

Maintenant, je sais que je peux analyser le fichier, envoyer le résultat au serveur et demander au navigateur de le télécharger à nouveau. Mais en réalité, le serveur n'a rien à voir avec ce processus particulier, alors pourquoi l'impliquer? J'ai déjà le contenu du fichier désiré en mémoire. Est-il possible de proposer à l'utilisateur un téléchargement utilisant du JavaScript pur? (J'en doute, mais autant demander ...)

Et pour être clair: je ne cherche pas à accéder au système de fichiers à l'insu de l'utilisateur! L'utilisateur fournira un fichier (probablement par glisser-déposer), le script transformera le fichier en mémoire et il sera invité à télécharger le résultat. Toutes ces activités devraient être "sûres" pour le navigateur.

[MODIFIER]: Je ne l'ai pas mentionné d'emblée, alors les affiches qui ont répondu "Flash" sont suffisamment valides, mais une partie de ce que je fais consiste à tenter de mettre en évidence ce que l'on peut faire avec du pur HTML5… Cas. (Bien que ce soit une réponse tout à fait valable pour quiconque fait une "vraie" application web.) Cela dit, il semble que je n’aie pas de chance, sauf si je veux impliquer le serveur. Merci quand même!

296
Toji

OK, créer une donnée: URI me convient parfaitement, grâce à Matthew et Dennkster qui ont précisé cette option! Voici comment je le fais:

1) récupérez tout le contenu dans une chaîne appelée "contenu" (par exemple, en le créant initialement ou en lisant innerHTML de la balise d’une page déjà construite).

2) Construisez l'URI des données:

uriContent = "data:application/octet-stream," + encodeURIComponent(content);

Il y aura des limites de longueur en fonction du type de navigateur, etc., mais par ex. Firefox 3.6.12 fonctionne jusqu'à au moins 256k. Encoder en Base64 à la place en utilisant encodeURIComponent pourrait rendre les choses plus efficaces, mais pour moi c'était ok.

3) ouvrez une nouvelle fenêtre et "le redirigez" vers cette adresse URI pour indiquer l'emplacement de téléchargement de ma page JavaScript:

newWindow = window.open(uriContent, 'neuesDokument');

C'est ça.

247
Nøk

Solution simple pour les navigateurs prêts pour HTML5 ...

function download(filename, text) {
    var pom = document.createElement('a');
    pom.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
    pom.setAttribute('download', filename);

    if (document.createEvent) {
        var event = document.createEvent('MouseEvents');
        event.initEvent('click', true, true);
        pom.dispatchEvent(event);
    }
    else {
        pom.click();
    }
}

tilisation

download('test.txt', 'Hello world!');
260
Matěj Pokorný

HTML5 a défini une méthode window.saveAs(blob, filename). Il n'est supporté par aucun navigateur pour le moment. Mais il existe une bibliothèque de compatibilité appelée FileSaver.js qui ajoute cette fonction à la plupart des navigateurs modernes (y compris Internet Explorer 10+). Internet Explorer 10 prend en charge une méthode navigator.msSaveBlob(blob, filename) ( (MSDN )) utilisée dans FileSaver.js pour la prise en charge d'Internet Explorer.

J'ai écrit un blogging avec plus de détails sur ce problème.

79
panzi

Sauvegarde de gros fichiers

Les URI de données longs peuvent poser des problèmes de performances dans les navigateurs. Une autre option pour enregistrer les fichiers générés côté client consiste à placer leur contenu dans un objet Blob (ou Fichier) et à créer un lien de téléchargement à l'aide de URL.createObjectURL(blob) . Cela renvoie une URL qui peut être utilisée pour récupérer le contenu du blob. Le blob est stocké dans le navigateur jusqu'à ce que URL.revokeObjectURL() soit appelé sur l'URL ou que le document qui l'a créé soit fermé. La plupart des navigateurs Web ont prise en charge des URL d'objet , Opera Mini est le seul à ne pas les prendre en charge.

Forcer un téléchargement

Si les données sont du texte ou une image, le navigateur peut ouvrir le fichier au lieu de l'enregistrer sur le disque. Pour que le fichier soit téléchargé en cliquant sur le lien, vous pouvez utiliser l'attribut download. Cependant, tous les navigateurs Web n’ont pas prise en charge de l’attribut download . Une autre option consiste à utiliser application/octet-stream en tant que type mime du fichier, mais le fichier sera présenté comme un objet blob binaire, particulièrement hostile à l'utilisateur si vous ne spécifiez pas ou ne pouvez pas spécifier un nom de fichier. Voir aussi ' Forçage pour ouvrir la fenêtre "Enregistrer sous ..." ouverte au lien du texte, cliquez pour le pdf en HTML '.

Spécifier un nom de fichier

Si le blob est créé avec le constructeur de fichiers, vous pouvez également définir un nom de fichier, mais seuls quelques navigateurs Web (y compris Chrome et Firefox) ont prise en charge du constructeur de fichiers . Le nom de fichier peut également être spécifié en tant qu'argument de l'attribut download, mais il est soumis à une tonne de considérations de sécurité . Internet Explorer 10 et 11 fournit sa propre méthode, msSaveBlob , pour spécifier un nom de fichier.

Exemple de code

var file;
var data = [];
data.Push("This is a test\n");
data.Push("Of creating a file\n");
data.Push("In a browser\n");
var properties = {type: 'text/plain'}; // Specify the file's mime-type.
try {
  // Specify the filename using the File constructor, but ...
  file = new File(data, "file.txt", properties);
} catch (e) {
  // ... fall back to the Blob constructor if that isn't supported.
  file = new Blob(data, properties);
}
var url = URL.createObjectURL(file);
document.getElementById('link').href = url;
<a id="link" target="_blank" download="file.txt">Download</a>
42
bcmpinc
function download(content, filename, contentType)
{
    if(!contentType) contentType = 'application/octet-stream';
        var a = document.createElement('a');
        var blob = new Blob([content], {'type':contentType});
        a.href = window.URL.createObjectURL(blob);
        a.download = filename;
        a.click();
}
32
Yassir Ennazk

Jetez un coup d'œil à Downloadify de Doug Neiner, qui est une interface JavaScript basée sur Flash pour le faire.

Downloadify est une petite bibliothèque JavaScript + Flash qui permet de générer et de sauvegarder des fichiers à la volée, dans le navigateur, sans interaction du serveur.

25
Pekka 웃

Solution simple!

<a download="My-FileName.txt" href="data:application/octet-stream,HELLO-WORLDDDDDDDD">Click here</a>

Fonctionne dans tous les navigateurs modernes.

16
T.Todua

J'ai utilisé FileSaver ( https://github.com/eligrey/FileSaver.js ) et cela fonctionne très bien.
Par exemple, j'ai créé cette fonction pour exporter les journaux affichés sur une page.
Vous devez passer un tableau pour l'instanciation du Blob, alors je ne l'ai peut-être pas écrit correctement, mais cela fonctionne pour moi.
Juste au cas où, soyez prudent avec le remplacement: c'est la syntaxe pour le rendre global, sinon il ne remplacera que le premier qu'il rencontre.

exportLogs : function(){
    var array = new Array();

    var str = $('#logs').html();
    array[0] = str.replace(/<br>/g, '\n\t');

    var blob = new Blob(array, {type: "text/plain;charset=utf-8"});
    saveAs(blob, "example.log");
}
10
Razakhel

Vous pouvez générer un RI de données . Cependant, il existe des limitations spécifiques au navigateur.

10
Matthew Flaschen

J'ai trouvé deux approches simples qui fonctionnent pour moi. Premièrement, en utilisant un élément a déjà cliqué et en injectant les données de téléchargement. Et deuxièmement, générer un élément a avec les données de téléchargement, exécuter a.click() et le supprimer à nouveau. Mais la seconde approche ne fonctionne que si elle est également invoquée par un utilisateur. (Certains) Blocage du navigateur click() provenant d'autres contextes, par exemple lors du chargement ou déclenchés après un délai d'attente (setTimeout).

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="UTF-8">
    <script type="text/javascript">
      function linkDownload(a, filename, content) {
        contentType =  'data:application/octet-stream,';
        uriContent = contentType + encodeURIComponent(content);
        a.setAttribute('href', uriContent);
        a.setAttribute('download', filename);
      }
      function download(filename, content) {
        var a = document.createElement('a');
        linkDownload(a, filename, content);
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
      }
    </script>
   </head>
  <body>
    <a href="#" onclick="linkDownload(this, 'test.txt', 'Hello World!');">download</a>
    <button onclick="download('test.txt', 'Hello World!');">download</button>
  </body>
</html>
8
maikel

Voici un lien vers la méthode d'URI des données suggérée par Mathew, cela fonctionnait sur safari, mais pas bien car je ne pouvais pas définir le type de fichier, il est enregistré comme "inconnu" et je dois y revenir plus tard et le modifier dans l'ordre pour voir le fichier ...

http://www.nihilogic.dk/labs/canvas2image/

6
Dennkster

Vous pouvez utiliser localStorage. Ceci est l'équivalent Html5 des cookies. Il semble que cela fonctionne sur Chrome et Firefox MAIS sous Firefox, je devais le télécharger sur un serveur. Autrement dit, les tests directement sur mon ordinateur à la maison ne fonctionnaient pas.

Je travaille des exemples HTML5. Allez à http://faculty.purchase.edu/jeanine.meyer/html5/html5explain.html et faites défiler jusqu'au labyrinthe. Les informations permettant de reconstruire le labyrinthe sont stockées à l'aide de localStorage.

Je suis arrivé à cet article à la recherche de HTML5 JavaScript pour le chargement et l'utilisation de fichiers XML. Est-ce la même chose que l'ancien HTML et JavaScript?

4
Jeanine

Comme mentionné précédemment, l'API Fichier , ainsi que les API FileWriter et FileSystem peuvent être utilisés pour stocker des fichiers sur la machine d'un client à partir du contexte d'un onglet/fenêtre du navigateur.

Cependant, vous devez être conscient de plusieurs choses concernant ces deux dernières API:

  • Les implémentations des API n'existent actuellement que dans les navigateurs basés sur Chromium (Chrome et Opera).
  • Les deux API ont été retirées de la piste des normes W3C le 24 avril 2014 et sont à présent des solutions propriétaires.
  • La suppression des API (désormais propriétaires) de la mise en œuvre de navigateurs dans le futur est une possibilité
  • Un sandbox (un emplacement sur le disque en dehors duquel les fichiers ne peuvent produire aucun effet) est utilisé pour stocker les fichiers créés avec les API
  • Un système de fichiers virtuel (une structure de répertoires qui n'existe pas nécessairement sur le disque sous la même forme que celle utilisée lors d'un accès depuis le navigateur) est utilisé les fichiers créés avec les API

Voici des exemples simples de la façon dont les API sont utilisées, directement et indirectement, pour ce faire:

BakedGoods *

bakedGoods.get({
        data: ["testFile"],
        storageTypes: ["fileSystem"],
        options: {fileSystem:{storageType: Window.PERSISTENT}},
        complete: function(resultDataObj, byStorageTypeErrorObj){}
});

Utilisation des API brutes File, FileWriter et FileSystem

function onQuotaRequestSuccess(grantedQuota)
{

    function saveFile(directoryEntry)
    {

        function createFileWriter(fileEntry)
        {

            function write(fileWriter)
            {
                var dataBlob = new Blob(["Hello world!"], {type: "text/plain"});
                fileWriter.write(dataBlob);              
            }

            fileEntry.createWriter(write);
        }

        directoryEntry.getFile(
            "testFile", 
            {create: true, exclusive: true},
            createFileWriter
        );
    }

    requestFileSystem(Window.PERSISTENT, grantedQuota, saveFile);
}

var desiredQuota = 1024 * 1024 * 1024;
var quotaManagementObj = navigator.webkitPersistentStorage;
quotaManagementObj.requestQuota(desiredQuota, onQuotaRequestSuccess);

Bien que les API FileSystem et FileWriter ne soient plus sur la voie des normes, leur utilisation peut être justifiée dans certains cas, à mon avis, pour les raisons suivantes:

  • L'intérêt renouvelé des vendeurs de navigateurs non-implémentés peut leur redonner tout leur sens.
  • La pénétration des navigateurs (basés sur le chrome) sur le marché est élevée
  • Google (principal contributeur à Chrome) n'a pas donné de date de fin de vie aux API

Que "certains cas" englobe le vôtre, cependant, c'est à vous de décider.

* BakedGoods est mis à jour par personne d'autre que ce gars-là, juste ici:)

3
Kevin

Ce fil de discussion était précieux pour comprendre comment générer un fichier binaire et Demander de télécharger le fichier nommé, le tout dans du code client sans serveur.

La première étape pour moi a été de générer le blob binaire à partir des données que je sauvegardais. Il y a beaucoup d'exemples pour faire cela pour un seul type binaire, dans mon cas, j'ai un format binaire avec plusieurs types que vous pouvez transmettre en tant que tableau pour créer le blob.

saveAnimation: function() {

    var device = this.Device;
    var maxRow = ChromaAnimation.getMaxRow(device);
    var maxColumn = ChromaAnimation.getMaxColumn(device);
    var frames = this.Frames;
    var frameCount = frames.length;

    var writeArrays = [];


    var writeArray = new Uint32Array(1);
    var version = 1;
    writeArray[0] = version;
    writeArrays.Push(writeArray.buffer);
    //console.log('version:', version);


    var writeArray = new Uint8Array(1);
    var deviceType = this.DeviceType;
    writeArray[0] = deviceType;
    writeArrays.Push(writeArray.buffer);
    //console.log('deviceType:', deviceType);


    var writeArray = new Uint8Array(1);
    writeArray[0] = device;
    writeArrays.Push(writeArray.buffer);
    //console.log('device:', device);


    var writeArray = new Uint32Array(1);
    writeArray[0] = frameCount;
    writeArrays.Push(writeArray.buffer);
    //console.log('frameCount:', frameCount);

    for (var index = 0; index < frameCount; ++index) {

      var frame = frames[index];

      var writeArray = new Float32Array(1);
      var duration = frame.Duration;
      if (duration < 0.033) {
        duration = 0.033;
      }
      writeArray[0] = duration;
      writeArrays.Push(writeArray.buffer);

      //console.log('Frame', index, 'duration', duration);

      var writeArray = new Uint32Array(maxRow * maxColumn);
      for (var i = 0; i < maxRow; ++i) {
        for (var j = 0; j < maxColumn; ++j) {
          var color = frame.Colors[i][j];
          writeArray[i * maxColumn + j] = color;
        }
      }
      writeArrays.Push(writeArray.buffer);
    }

    var blob = new Blob(writeArrays, {type: 'application/octet-stream'});

    return blob;
}

L'étape suivante consiste à demander au navigateur de demander à l'utilisateur de télécharger ce blob avec un nom prédéfini.

Tout ce dont j'avais besoin était un lien nommé que j'avais ajouté dans le HTML5 et que je pouvais réutiliser pour renommer le nom de fichier initial. Je l'ai gardé caché car le lien n'a pas besoin d'être affiché.

<a id="lnkDownload" style="display: none" download="client.chroma" href="" target="_blank"></a>

La dernière étape consiste à demander à l'utilisateur de télécharger le fichier.

var data = animation.saveAnimation();
var uriContent = URL.createObjectURL(data);
var lnkDownload = document.getElementById('lnkDownload');
lnkDownload.download = 'theDefaultFileName.extension';
lnkDownload.href = uriContent;
lnkDownload.click();
2
tgraupmann

essayer

let a = document.createElement('a');
a.href = "data:application/octet-stream,"+encodeURIComponent('"My DATA"');
a.download = 'myFile.json';
a.click();
2
Kamil Kiełczewski

Voici un tutoriel pour exporter des fichiers au format Zip:

Avant de commencer, il existe une bibliothèque pour enregistrer les fichiers. Le nom de la bibliothèque est fileSaver.js. Vous pouvez trouver cette bibliothèque ici. Commençons maintenant, incluez les bibliothèques requises:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.4/jszip.min.js"  type="text/javascript"></script>
<script type="text/javascript" src="https://fastcdn.org/FileSaver.js/1.1.20151003/FileSaver.js" ></script>

Maintenant, copiez ce code et ce code téléchargera un fichier Zip avec un fichier hello.txt ayant le contenu Hello World. Si tout fonctionne correctement, cela téléchargera un fichier.

<script type="text/javascript">
    var Zip = new JSZip();
    Zip.file("Hello.txt", "Hello World\n");
    Zip.generateAsync({type:"blob"})
    .then(function(content) {
        // see FileSaver.js
        saveAs(content, "file.Zip");
    });
</script>

Cela téléchargera un fichier nommé file.Zip. Vous pouvez en lire plus ici: http://www.wapgee.com/story/248/guide-to-create-Zip-files-using-javascript-by-using-jszip-library

1
Ilyas karim