web-dev-qa-db-fra.com

Créer un fichier en mémoire que l'utilisateur peut télécharger, et non par le serveur

Existe-t-il un moyen de créer un fichier texte côté client et d’inviter l’utilisateur à le télécharger, sans interaction avec le serveur? puis-je créer et les inviter à le sauvegarder?

696
Joseph Silber

Vous pouvez utiliser des URI de données. La prise en charge du navigateur varie. voir Wikipedia . Exemple:

<a href="data:application/octet-stream;charset=utf-16le;base64,//5mAG8AbwAgAGIAYQByAAoA">text file</a>

Le flux d'octets consiste à forcer une invite de téléchargement. Sinon, il s'ouvrira probablement dans le navigateur.

Pour CSV, vous pouvez utiliser:

<a href="data:application/octet-stream,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A">CSV Octet</a>

Essayez la démo jsFiddle .

381
Matthew Flaschen

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

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

  element.style.display = 'none';
  document.body.appendChild(element);

  element.click();

  document.body.removeChild(element);
}
form * {
  display: block;
  margin: 10px;
}
<form onsubmit="download(this['name'].value, this['text'].value)">
  <input type="text" name="name" value="test.txt">
  <textarea name="text"></textarea>
  <input type="submit" value="Download">
</form>

Utilisation

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

Tous les exemples ci-dessus fonctionnent très bien dans Chrome et IE, mais échouent dans Firefox . Veuillez envisager d’ajouter une ancre au corps et de la supprimer après un clic.

var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob(['Test,Text'], {type: 'text/csv'}));
a.download = 'test.csv';

// Append anchor to body.
document.body.appendChild(a);
a.click();

// Remove anchor from body
document.body.removeChild(a);
169
naren

Toutes les solutions ci-dessus ne fonctionnaient pas dans tous les navigateurs. Voici ce qui fonctionne finalement sur IE 10+, Firefox et Chrome (et sans jQuery ou toute autre bibliothèque):

save: function(filename, data) {
    var blob = new Blob([data], {type: 'text/csv'});
    if(window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveBlob(blob, filename);
    }
    else{
        var elem = window.document.createElement('a');
        elem.href = window.URL.createObjectURL(blob);
        elem.download = filename;        
        document.body.appendChild(elem);
        elem.click();        
        document.body.removeChild(elem);
    }
}

Notez que, selon votre situation, vous pouvez également appeler URL.revokeObjectURL après avoir supprimé elem. Selon la documentation pour URL.createObjectURL :

Chaque fois que vous appelez createObjectURL (), une nouvelle URL d'objet est créée, même si vous en avez déjà créée une pour le même objet. Chacun de ceux-ci doit être libéré en appelant URL.revokeObjectURL () lorsque vous n'en avez plus besoin. Les navigateurs les publient automatiquement lorsque le document est déchargé. Toutefois, pour optimiser les performances et l'utilisation de la mémoire, vous devez le faire s'il existe des moments sûrs où vous pouvez les décharger explicitement.

162
Ludovic Feltz

J'utilise heureusement FileSaver.js . Sa compatibilité est plutôt bonne (IE10 + et tout le reste), et son utilisation est très simple:

var blob = new Blob(["some text"], {
    type: "text/plain;charset=utf-8;",
});
saveAs(blob, "thing.txt");
106

La méthode suivante fonctionne dans IE11 +, Firefox 25+ et Chrome 30+:

<a id="export" class="myButton" download="" href="#">export</a>
<script>
    function createDownloadLink(anchorSelector, str, fileName){
        if(window.navigator.msSaveOrOpenBlob) {
            var fileData = [str];
            blobObject = new Blob(fileData);
            $(anchorSelector).click(function(){
                window.navigator.msSaveOrOpenBlob(blobObject, fileName);
            });
        } else {
            var url = "data:text/plain;charset=utf-8," + encodeURIComponent(str);
            $(anchorSelector).attr("download", fileName);               
            $(anchorSelector).attr("href", url);
        }
    }

    $(function () {
        var str = "hi,file";
        createDownloadLink("#export",str,"file.txt");
    });

</script>

Voir cela en action: http://jsfiddle.net/Kg7eA/

Firefox et Chrome prennent en charge l'URI des données pour la navigation, ce qui nous permet de créer des fichiers en naviguant vers un URI de données, alors que IE ne le prend pas en charge à des fins de sécurité. 

D'autre part, IE possède une API pour enregistrer un blob, qui peut être utilisé pour créer et télécharger des fichiers.

22
dinesh ygv

Cette solution est extraite directement du référentiel github de tiddlywiki (tiddlywiki.com). J'ai utilisé tiddlywiki dans presque tous les navigateurs et cela fonctionne comme un charme:

function(filename,text){
    // Set up the link
    var link = document.createElement("a");
    link.setAttribute("target","_blank");
    if(Blob !== undefined) {
        var blob = new Blob([text], {type: "text/plain"});
        link.setAttribute("href", URL.createObjectURL(blob));
    } else {
        link.setAttribute("href","data:text/plain," + encodeURIComponent(text));
    }
    link.setAttribute("download",filename);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

Github repo: Module de sauvegarde

11
Danielo515

Solution qui fonctionne sur IE10:

var csvContent=data; //here we load our csv data 
var blob = new Blob([csvContent],{
    type: "text/csv;charset=utf-8;"
});

navigator.msSaveBlob(blob, "filename.csv")
10
Dzarek

Si vous souhaitez simplement convertir une chaîne en vue de son téléchargement, vous pouvez essayer avec jQuery.

$('a.download').attr('href', 'data:application/csv;charset=utf-8,' + encodeURI(data));
9
Rick
var element = document.createElement('a');
element.setAttribute('href', 'data:text/text;charset=utf-8,' +      encodeURI(data));
element.setAttribute('download', "fileName.txt");
element.click();
7
MANVENDRA LODHI

Comme mentionné précédemment, filesaver est un excellent package pour travailler avec des fichiers côté client. Mais, ce n'est pas bien avec les gros fichiers. StreamSaver.js est une solution alternative (indiquée dans FileServer.js) pouvant gérer des fichiers volumineux:

const fileStream = streamSaver.createWriteStream('filename.txt', size);
const writer = fileStream.getWriter();
for(var i = 0; i < 100; i++){
    var uint8array = new TextEncoder("utf-8").encode("Plain Text");
    writer.write(uint8array);
}
writer.close()
6
مصطفی

À compter d'avril 2014, les API FileSytem ne sont peut-être pas normalisées dans le W3C. Quiconque regarde la solution avec blob devrait enfiler avec prudence, je suppose.

HTML5 bat la tête

Liste de diffusion du W3C sur l'API FileSytem

5
pravin

Basé sur la réponse de @Rick qui était vraiment utile.

Vous devez échapper la chaîne data si vous voulez la partager de cette façon:

$('a.download').attr('href', 'data:application/csv;charset=utf-8,'+ encodeURI(data));

` Désolé, je ne peux pas commenter la réponse de @ Rick en raison de ma faible réputation actuelle dans StackOverflow.

Une suggestion edit a été partagée et rejetée.

5
atfornes

Vous pouvez même faire mieux que simplement des URI - en utilisant Chrome, vous êtes également en mesure de suggérer le nom que portera le fichier, comme expliqué dans cet article de blog sur la désignation d'un téléchargement lorsque vous utilisez des URI .

3
owencm

Le paquet js-file-download from github.com/kennethjiang/js-file-download gère les cas Edge pour la prise en charge du navigateur:

Voir le source pour voir comment il utilise les techniques mentionnées sur cette page.

Installation

yarn add js-file-download
npm install --save js-file-download

Usage

import fileDownload from 'js-file-download'

// fileDownload(data, filename, mime)
// mime is optional

fileDownload(data, 'filename.csv', 'text/csv')
0
Beau Smith

Nous pouvons utiliser le URL api, en particulier RL.createObjectURL () , et le Blob api pour encoder et télécharger à peu près n'importe quoi.

document.body.innerHTML += 
`<a id="download" download="PATTERN.json" href="${URL.createObjectURL(new Blob([JSON.stringify("HELLO WORLD", null, 2)]))}"> Click me</a>`
download.click()
download.outerHTML = ""

Bonus! Téléchargez n'importe quel objets cycliques , évitez les erreurs:

TypeError: valeur d'objet cyclique (Firefox) TypeError: Conversion

structure circulaire en JSON (Chrome et Opera) TypeError: Circular

référence en argument de valeur non pris en charge (Edge)

Utilisation de https://github.com/douglascrockford/JSON-js/blob/master/cycle.js

/* JSON.decycle */
if(typeof JSON.decycle!=="function"){JSON.decycle=function decycle(object,replacer){"use strict";var objects=new WeakMap();return(function derez(value,path){var old_path;var nu;if(replacer!==undefined){value=replacer(value)}
if(typeof value==="object"&&value!==null&&!(value instanceof Boolean)&&!(value instanceof Date)&&!(value instanceof Number)&&!(value instanceof RegExp)&&!(value instanceof String)){old_path=objects.get(value);if(old_path!==undefined){return{$ref:old_path}}
objects.set(value,path);if(Array.isArray(value)){nu=[];value.forEach(function(element,i){nu[i]=derez(element,path+"["+i+"]")})}else{nu={};Object.keys(value).forEach(function(name){nu[name]=derez(value[name],path+"["+JSON.stringify(name)+"]")})}
return nu}
return value}(object,"$"))}}


document.body.innerHTML += 
`<a id="download" download="PATTERN.json" href="${URL.createObjectURL(new Blob([JSON.stringify(JSON.decycle(document), null, 2)]))}"></a>`
download.click()
0
NVRM

Pour moi, cela fonctionnait parfaitement, avec le même nom de fichier et la même extension téléchargés.

<a href={"data:application/octet-stream;charset=utf-16le;base64," + file64 } download={title} >{title}</a>

'titre' est le nom du fichier avec l'extension i.e, sample.pdf, waterfall.jpg, etc.

'file64' est le contenu base64 quelque chose comme ceci i.e, Ww6IDEwNDAsIFNsaWRpbmdTY2FsZUdyb3VwOiAiR3JvdXAgQiIsIE1lZGljYWxWaXNpdEZsYXRGZWU6IDM1LCBEZW50YWxQYXltZW50UGVyY2VudGFnZTogMjUsIFByb2NlZHVyZVBlcmNlbnQ6IDcwLKCFfSB7IkdyYW5kVG90YWwiOjEwNDAsIlNsaWRpbmdTY2FsZUdyb3VwIjoiR3JvdXAgQiIsIk1lZGljYWxWaXNpdEZsYXRGZWUiOjM1LCJEZW50YWxQYXltZW50UGVyY2VudGFnZSI6MjUsIlByb2NlZHVyZVBlcmNlbnQiOjcwLCJDcmVhdGVkX0J5IjoiVGVycnkgTGVlIiwiUGF0aWVudExpc3QiOlt7IlBhdGllbnRO

0
abdul

Cette fonction ci-dessous a fonctionné.

 private createDownloadableCsvFile(fileName, content) {
   let link = document.createElement("a");
   link.download = fileName;
   link.href = `data:application/octet-stream,${content}`;
   return link;
 }
0
bountyhunter