How to create a file in memory for user to download, but not through server?
JavascriptFileWeb ApplicationsClient SideJavascript Problem Overview
Is there any way I can create a text file on the client side and prompt the user to download it, without any interaction with the server? I know I can't write directly to their machine (security and all), but can I create and prompt them to save it?
Javascript Solutions
Solution 1 - Javascript
Simple solution for HTML5 ready browsers...
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>
Usage
download('test.txt', 'Hello world!');
Solution 2 - Javascript
You can use data URIs. Browser support varies; see Wikipedia. Example:
<a href="data:application/octet-stream;charset=utf-16le;base64,//5mAG8AbwAgAGIAYQByAAoA">text file</a>
The octet-stream is to force a download prompt. Otherwise, it will probably open in the browser.
For CSV, you can use:
<a href="data:application/octet-stream,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A">CSV Octet</a>
Try the jsFiddle demo.
Solution 3 - Javascript
An example for IE 10+, Firefox and Chrome (and without jQuery or any other library):
function save(filename, data) {
const blob = new Blob([data], {type: 'text/csv'});
if(window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, filename);
}
else{
const elem = window.document.createElement('a');
elem.href = window.URL.createObjectURL(blob);
elem.download = filename;
document.body.appendChild(elem);
elem.click();
document.body.removeChild(elem);
}
}
Note that, depending on your situation, you may also want to call URL.revokeObjectURL after removing elem
. According to the docs for URL.createObjectURL:
> Each time you call createObjectURL(), a new object URL is created, even if you've already created one for the same object. Each of these must be released by calling URL.revokeObjectURL() when you no longer need them. Browsers will release these automatically when the document is unloaded; however, for optimal performance and memory usage, if there are safe times when you can explicitly unload them, you should do so.
Solution 4 - Javascript
All of the above example works just fine in chrome and IE, but fail in Firefox. Please do consider appending an anchor to the body and removing it after click.
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);
Solution 5 - Javascript
I'm happily using FileSaver.js. Its compatibility is pretty good (IE10+ and everything else), and it's very simple to use:
var blob = new Blob(["some text"], {
type: "text/plain;charset=utf-8;",
});
saveAs(blob, "thing.txt");
Solution 6 - Javascript
The following method works in IE11+, Firefox 25+ and 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>
See this in Action: http://jsfiddle.net/Kg7eA/
Firefox and Chrome support data URI for navigation, which allows us to create files by navigating to a data URI, while IE doesn't support it for security purposes.
On the other hand, IE has API for saving a blob, which can be used to create and download files.
Solution 7 - Javascript
The package js-file-download from github.com/kennethjiang/js-file-download handles edge cases for browser support:
View source to see how it uses techniques mentioned on this 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')
Solution 8 - Javascript
This solution is extracted directly from tiddlywiki's (tiddlywiki.com) github repository. I have used tiddlywiki in almost all browsers and it works like a charm:
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: Download saver module
Solution 9 - Javascript
We can use the URL api, in particular URL.createObjectURL(), and the Blob api to encode and download pretty much anything.
If your download is small, this works fine:
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 = ""
If your download is huge, instead of using the DOM, a better way is to create a link element with the download parameters, and trigger a click.
Notice the link element isn't appended to the document but the click work anyway! This is possible to create a download of many hundreds of Mo this way.
const stack = {
some: "stuffs",
alot: "of them!"
}
BUTTONDOWNLOAD.onclick = (function(){
let j = document.createElement("a")
j.download = "stack_"+Date.now()+".json"
j.href = URL.createObjectURL(new Blob([JSON.stringify(stack, null, 2)]))
j.click()
})
<button id="BUTTONDOWNLOAD">DOWNLOAD!</button>
Bonus! Download any cyclic objects, avoid the errors:
> TypeError: cyclic object value (Firefox) TypeError: Converting > > circular structure to JSON (Chrome and Opera) TypeError: Circular > > reference in value argument not supported (Edge)
Using https://github.com/douglascrockford/JSON-js/blob/master/cycle.js
On this example, downloading the document
object as json.
/* 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()
Solution 10 - Javascript
Use Blob:
function download(content, mimeType, filename){
const a = document.createElement('a') // Create "a" element
const blob = new Blob([content], {type: mimeType}) // Create a blob (file-like object)
const url = URL.createObjectURL(blob) // Create an object URL from blob
a.setAttribute('href', url) // Set "a" element link
a.setAttribute('download', filename) // Set download filename
a.click() // Start downloading
}
Blob is being supported by all modern browsers.
Caniuse support table for Blob:
https://i.stack.imgur.com/ZkVf1.png">
https://jsfiddle.net/Stelios2020/ukmf5304/6/">Here is a Fiddle
And here https://developer.mozilla.org/en-US/docs/Web/API/Blob">MDN Docs
Solution 11 - Javascript
If you just want to convert a string to be available for download you can try this using jQuery.
$('a.download').attr('href', 'data:application/csv;charset=utf-8,' + encodeURI(data));
Solution 12 - Javascript
Solution that work on IE10: (I needed a csv file, but it's enough to change type and filename to txt)
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")
Solution 13 - Javascript
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);
}
// Start file download.
download("hello.txt","This is the content of my file :)");
Original article : https://ourcodeworld.com/articles/read/189/how-to-create-a-file-and-generate-a-download-with-javascript-in-the-browser-without-a-server
Solution 14 - Javascript
As mentioned before, filesaver is a great package to work with files on the client side. But, it is not do well with large files. StreamSaver.js is an alternative solution (which is pointed in FileServer.js) that can handle large files:
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()
Solution 15 - Javascript
var element = document.createElement('a');
element.setAttribute('href', 'data:text/text;charset=utf-8,' + encodeURI(data));
element.setAttribute('download', "fileName.txt");
element.click();
Solution 16 - Javascript
Based on @Rick answer which was really helpful.
You have to scape the string data
if you want to share it this way:
$('a.download').attr('href', 'data:application/csv;charset=utf-8,'+ encodeURI(data));
` Sorry I can not comment on @Rick's answer due to my current low reputation in StackOverflow.
An edit suggestion was shared and rejected.
Solution 17 - Javascript
This below function worked.
private createDownloadableCsvFile(fileName, content) {
let link = document.createElement("a");
link.download = fileName;
link.href = `data:application/octet-stream,${content}`;
return link;
}
Solution 18 - Javascript
The following method works in IE10+, Edge, Opera, FF and Chrome:
const saveDownloadedData = (fileName, data) => {
if(~navigator.userAgent.indexOf('MSIE') || ~navigator.appVersion.indexOf('Trident/')) { /* IE9-11 */
const blob = new Blob([data], { type: 'text/csv;charset=utf-8;' });
navigator.msSaveBlob(blob, fileName);
} else {
const link = document.createElement('a')
link.setAttribute('target', '_blank');
if(Blob !== undefined) {
const blob = new Blob([data], { type: 'text/plain' });
link.setAttribute('href', URL.createObjectURL(blob));
} else {
link.setAttribute('href', 'data:text/plain,' + encodeURIComponent(data));
}
~window.navigator.userAgent.indexOf('Edge')
&& (fileName = fileName.replace(/[&\/\\#,+$~%.'':*?<>{}]/g, '_')); /* Edge */
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
So, just call the function:
saveDownloadedData('test.txt', 'Lorem ipsum');
Solution 19 - Javascript
For me this worked perfectly, with the same filename and extension getting downloaded
<a href={"data:application/octet-stream;charset=utf-16le;base64," + file64 } download={title} >{title}</a>
'title' is the file name with extension i.e, sample.pdf
, waterfall.jpg
, etc..
'file64' is the base64 content something like this i.e, Ww6IDEwNDAsIFNsaWRpbmdTY2FsZUdyb3VwOiAiR3JvdXAgQiIsIE1lZGljYWxWaXNpdEZsYXRGZWU6IDM1LCBEZW50YWxQYXltZW50UGVyY2VudGFnZTogMjUsIFByb2NlZHVyZVBlcmNlbnQ6IDcwLKCFfSB7IkdyYW5kVG90YWwiOjEwNDAsIlNsaWRpbmdTY2FsZUdyb3VwIjoiR3JvdXAgQiIsIk1lZGljYWxWaXNpdEZsYXRGZWUiOjM1LCJEZW50YWxQYXltZW50UGVyY2VudGFnZSI6MjUsIlByb2NlZHVyZVBlcmNlbnQiOjcwLCJDcmVhdGVkX0J5IjoiVGVycnkgTGVlIiwiUGF0aWVudExpc3QiOlt7IlBhdGllbnRO
Solution 20 - Javascript
I would use an <a></a>
tag then set the href='path'
. Afterwards, place an image in between the <a>
elements so that I can have a visual to see it. If you wanted to, you could create a function that will change the href
so that it won't just be the same link but be dynamic.
Give the <a>
tag an id
as well if you want to access it with javascript.
Starting with the HTML Version:
<a href="mp3/tupac_shakur-how-do-you-want-it.mp3" download id="mp3Anchor">
<img src="some image that you want" alt="some description" width="100px" height="100px" />
</a>
Now with JavaScript:
*Create a small json file*;
const array = [
"mp3/tupac_shakur-how-do-you-want-it.mp3",
"mp3/spice_one-born-to-die.mp3",
"mp3/captain_planet_theme_song.mp3",
"mp3/tenchu-intro.mp3",
"mp3/resident_evil_nemesis-intro-theme.mp3"
];
//load this function on window
window.addEventListener("load", downloadList);
//now create a function that will change the content of the href with every click
function downloadList() {
var changeHref=document.getElementById("mp3Anchor");
var j = -1;
changeHref.addEventListener("click", ()=> {
if(j < array.length-1) {
j +=1;
changeHref.href=""+array[j];
}
else {
alert("No more content to download");
}
}
Solution 21 - Javascript
Download file with extensions or without extensions in the example, I am using JSON. You may add your data and extensions. You may use 'MAC-Addresses.json' here, as per your wish. If you want to add an extension, add there, else, just write the file name without extensions.
let myJson = JSON.stringify(yourdata);
let element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(myJson));
element.setAttribute('download', 'MAC-Addresses.json');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
Solution 22 - Javascript
If the file contains text data, a technique I use is to put the text into a textarea element and have the user select it (click in textarea then ctrl-A) then copy followed by a paste to a text editor.