28

There's already a solution for writing file JSON online but I want to save json file locally. I've tried to use this example http://jsfiddle.net/RZBbY/10/ It creates a link to download the file, using this call a.attr('href', 'data:application/x-json;base64,' + btoa(t.val())).show(); Is there a way to save the file locally instead of providing a downloadable link? There are other types of conversion beyond data:application/x-json;base64?

Here's my code:

<!DOCTYPE html>
<head> 
    <meta charset="utf-8">
    <title>jQuery UI Sortable - Default functionality</title>

    <link rel="stylesheet" href="http://jqueryui.com/themes/base/jquery.ui.all.css">
    <script src="http://jqueryui.com//jquery-1.7.2.js"></script>
    <script src="http://jqueryui.com/ui/jquery.ui.core.js"></script>
    <script src="http://jqueryui.com/ui/jquery.ui.widget.js"></script>
    <script src="http://jqueryui.com/ui/jquery.ui.mouse.js"></script>
    <script src="http://jqueryui.com/ui/jquery.ui.sortable.js"></script>
        <script src="http://jqueryui.com/ui/jquery.ui.accordion.js"></script>
    <link rel="stylesheet" href="http://jqueryui.com/demos/demos.css">        
    <meta charset="utf-8">
    <style>a { font: 12px Arial; color: #ac9095; }</style>
<script type='text/javascript'>
$(document).ready(function() {
var f = $('form'), a = $('a'),
    i = $('input'), t = $('textarea');
       
$('#salva').click(function() {
    var o = {}, v = t.val();
    
    a.hide();//nasconde il contenuto
    i.each(function() { 
    o[this.name] = $(this).val(); });
    if (v === '') {
        t.val("[\n " + JSON.stringify(o) + " \n]")         
    }
    else {
        t.val(v.substr(0, v.length - 3));
        t.val(t.val() + ",\n " + JSON.stringify(o) +  " \n]")  
    }
});
});

$('#esporta').bind('click', function() {
    a.attr('href', 'data:application/x-json;base64,' + btoa(t.val())).show();
        
});
</script>
</head>
<body>
    <form>
        <label>Nome</label> <input type="text" name="nome"><br />
        <label>Cognome</label> <input type="text" name="cognome">
        <button type="button" id="salva">Salva</button>
    </form>        

    <textarea rows="10" cols="60"></textarea><br />
    <button type="button" id="esporta">Esporta dati</button>
    <a href="" style="display: none">Scarica Dati</a>
</body>
</html>
ccpizza
  • 28,968
  • 18
  • 162
  • 169
Mirko Cianfarani
  • 2,023
  • 1
  • 23
  • 39

8 Answers8

31

Based on http://html5-demos.appspot.com/static/a.download.html:

var fileContent = "My epic novel that I don't want to lose.";
var bb = new Blob([fileContent ], { type: 'text/plain' });
var a = document.createElement('a');
a.download = 'download.txt';
a.href = window.URL.createObjectURL(bb);
a.click();

Modified the original fiddle: http://jsfiddle.net/9av2mfjx/

Stanislav
  • 4,389
  • 2
  • 33
  • 35
13

You should check the download attribute and the window.URL method because the download attribute doesn't seem to like data URI. This example by Google is pretty much what you are trying to do.

Calvein
  • 2,111
  • 13
  • 28
  • +1 I've tried data uri schema in the past, it works, but it decides how to name the file you end up with so its pretty much useless. I tried this in Firefox, Safari, Opera and Chrome on Mac, Safari and Opera have no "BlobBuilder" So the disclaimer about "only Chrome dev channel (14.0.835.15+) supports this attribute" is partially true. At this time it works on FireFox, it fails in Safari and Opera. – Shanimal Oct 17 '12 at 12:56
  • Blob Builder is supposedly working in MSIE as well... http://ie.microsoft.com/testdrive/HTML5/BlobBuilder/ – Shanimal Oct 17 '12 at 13:30
  • 4
    Link is broken. – SandPiper Apr 24 '21 at 23:06
  • It seams that the page was removed in May 2020. But it still can be found in the archive few days before removal [here](https://web.archive.org/web/20200508082503/http://html5-demos.appspot.com/static/a.download.html). – holem Oct 15 '22 at 13:28
9

It is not possible to save file locally without involving the local client (browser machine) as I could be a great threat to client machine. You can use link to download that file. If you want to store something like Json data on local machine you can use LocalStorage provided by the browsers, Web Storage

David Renner
  • 454
  • 3
  • 15
Adil
  • 146,340
  • 25
  • 209
  • 204
  • 7
    Thanks, it could be providing wrong information but I did not know this before and used to take help from it. Could be please tell me what is wrong in the particular link I have given in the answer. – Adil Jun 17 '12 at 13:33
  • 1
    Thx!!! Now i studying Web storage but There are other types of conversion beyond data:application/x-json;base64? – Mirko Cianfarani Jun 17 '12 at 16:36
  • 1
    Uao ROdneyrehm I did not know of this site wfools.com – Mirko Cianfarani Jun 17 '12 at 16:45
6

The possible ways to create and save files in Javascript are:

Use a library called FileSaver

saveAs(new File(["CONTENT"], "demo.txt", {type: "text/plain;charset=utf-8"}));

Create a blob object and offer a “save as”.

var a = document.createElement("a");
a.href = window.URL.createObjectURL(new Blob(["CONTENT"], {type: "text/plain"}));
a.download = "demo.txt";
a.click();

Upload the data, save it on the server.

var data = new FormData();
data.append("upfile", new Blob(["CONTENT"], {type: "text/plain"}));
fetch("SERVER.SCRIPT", { method: "POST", body: data });

Create a writable file stream.

const fileHandle = await window.showSaveFilePicker();
const fileStream = await fileHandle.createWritable();
await fileStream.write(new Blob(["CONTENT"], {type: "text/plain"}));
await fileStream.close();

In NodeJS, simply use the file system module

 require("fs").writeFile("demo.txt", "Foo bar!");

<!-- (A) LOAD FILE SAVER -->
<!-- https://cdnjs.com/libraries/FileSaver.js -->
<!-- https://github.com/eligrey/FileSaver.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
 
<script>
// (B) "SAVE AS"
var myFile = new File(["CONTENT"], "demo.txt", {type: "text/plain;charset=utf-8"});
saveAs(myFile);
</script>

// (A) CREATE BLOB OBJECT
var myBlob = new Blob(["CONTENT"], {type: "text/plain"});

// (B) CREATE DOWNLOAD LINK
var url = window.URL.createObjectURL(myBlob);
var anchor = document.createElement("a");
anchor.href = url;
anchor.download = "demo.txt";
    
// (C) "FORCE DOWNLOAD"
// NOTE: MAY NOT ALWAYS WORK DUE TO BROWSER SECURITY
// BETTER TO LET USERS CLICK ON THEIR OWN
anchor.click();
window.URL.revokeObjectURL(url);
document.removeChild(anchor);

    <script>
    function blobajax () {
      // (A) CREATE BLOB OBJECT
      var myBlob = new Blob(["CONTENT"], {type: "text/plain"});
    
      // (B) FORM DATA
      var data = new FormData();
      data.append("upfile", myBlob);
    
      // (C) AJAX UPLOAD TO SERVER
      fetch("3b-upload.php", {
        method: "POST",
        body: data
      })
      .then((res) => { return res.text(); })
      .then((txt) => { console.log(txt); });
    }
    </script>
    <input type="button" value="Go" onclick="blobajax()"/>

    <script>
    async function saveFile() {
      // (A) CREATE BLOB OBJECT
      var myBlob = new Blob(["CONTENT"], {type: "text/plain"});
     
      // (B) FILE HANDLER & FILE STREAM
      const fileHandle = await window.showSaveFilePicker({
        types: [{
          description: "Text file",
          accept: {"text/plain": [".txt"]}
        }]
      });
      const fileStream = await fileHandle.createWritable();
     
      // (C) WRITE FILE
      await fileStream.write(myBlob);
      await fileStream.close();
    }
    </script>
    
    <input type="button" value="Save File" onclick="saveFile()"/>

// (A) LOAD FILE SYSTEM MODULE
// https://nodejs.org/api/fs.html
const fs = require("fs");

// (B) WRITE TO FILE
fs.writeFile("demo.txt", "CONTENT", "utf8", (error, data) => {
  console.log("Write complete");
  console.log(error);
  console.log(data);
});

/* (C) READ FROM FILE
fs.readFile("demo.txt", "utf8", (error, data) => {
  console.log("Read complete");
  console.log(error);
  console.log(data);
});
*/
مهدی
  • 333
  • 3
  • 6
3

It all depends on what you are trying to achieve with "saving locally". Do you want to allow the user to download the file? then <a download> is the way to go. Do you want to save it locally, so you can restore your application state? Then you might want to look into the various options of WebStorage. Specifically localStorage or IndexedDB. The FilesystemAPI allows you to create local virtual file systems you can store arbitrary data in.

rodneyrehm
  • 13,442
  • 1
  • 40
  • 56
2

So, your real question is: "How can JavaScript save to a local file?"

Take a look at http://www.tiddlywiki.com/

They save their HTML page locally after you have "changed" it internally.

[ UPDATE 2016.01.31 ]

TiddlyWiki original version saved directly. It was quite nice, and saved to a configurable backup directory with the timestamp as part of the backup filename.

TiddlyWiki current version just downloads it as any file download. You need to do your own backup management. :(

[ END OF UPDATE

The trick is, you have to open the page as file:// not as http:// to be able to save locally.

The security on your browser will not let you save to _someone_else's_ local system, only to your own, and even then it isn't trivial.

-Jesse

Jesse Chisholm
  • 3,857
  • 1
  • 35
  • 29
  • 1
    Now I studying Tiddlywiki but There are other types of conversion beyond data:application/x-json;base64? – Mirko Cianfarani Jun 17 '12 at 16:38
  • tiddlywiki uses a java applet to access the local filesystem, not javascript. – st-boost Nov 14 '12 at 23:48
  • 3
    TiddlyWiki uses a Java applet for Safari and Opera. For IE it uses ActiveX and for Firefox/Camino it uses pure javascript (via privilegeManager) or a firefox extension (since privilegeManager was removed in v15). – dwurf Dec 29 '12 at 05:39
  • This jQuery plugin is extracted from TiddlyWiki, it works how @dwurf explained it. http://jquery.tiddlywiki.org/twFile.html – mahemoff Feb 02 '13 at 10:28
2

While most despise Flash, it is a viable option for providing "save" and "save as" functionality in your html/javascript environment.

I've created a widget called "OpenSave" that provides this functionality available here:

http://www.gieson.com/Library/projects/utilities/opensave/

-mike

bob
  • 7,539
  • 2
  • 46
  • 42
0

If you are using FireFox you can use the File HandleAPI

https://developer.mozilla.org/en-US/docs/Web/API/File_Handle_API

I had just tested it out and it works!

Kbdavis07
  • 1,012
  • 13
  • 24