Is it possible to write data to file using only JavaScript?
Asked Answered
P

11

294

I want to Write Data to existing file using JavaScript. I don't want to print it on console. I want to Actually Write data to abc.txt. I read many answered question but every where they are printing on console. at some place they have given code but its not working. So please can any one help me How to actually write data to File.

I referred the code but its not working: its giving error:

Uncaught TypeError: Illegal constructor

on chrome and

SecurityError: The operation is insecure.

on Mozilla

var f = "sometextfile.txt";

writeTextFile(f, "Spoon")
writeTextFile(f, "Cheese monkey")
writeTextFile(f, "Onion")

function writeTextFile(afilename, output)
{
  var txtFile =new File(afilename);
  txtFile.writeln(output);
  txtFile.close();
}

So can we actually write data to file using only Javascript or NOT?

Platen answered 9/1, 2014 at 5:54 Comment(2)
Check this out brother: #585734Councillor
#14795857Hokusai
S
112

Some suggestions for this -

  1. If you are trying to write a file on client machine, You can't do this in any cross-browser way. IE does have methods to enable "trusted" applications to use ActiveX objects to read/write file.
  2. If you are trying to save it on your server then simply pass on the text data to your server and execute the file writing code using some server side language.
  3. To store some information on the client side that is considerably small, you can go for cookies.
  4. Using the HTML5 API for Local Storage.
Selfpropulsion answered 9/1, 2014 at 6:1 Comment(5)
HTML5 API is maxed at 5 mb only.Foghorn
Yes, you can not write into system file without select it. Read Official Docs: w3.org/TR/file-upload/#security-discussionColloidal
Can you explain point 2. "If you are trying to save it on your server then simply pass on the text data to your server and execute the file writing code using some server side language." Can You give any link tutorial?Fettle
@Fettle it's pretty self explanatory , given the text data (coming from client) create/append to a file on server side. i.e write the file code on the server side.Bibliotheca
Local storage is limited to only 5MB in most browsers, so I would use IndexedDB to store larger files.Stettin
F
283

You can create files in browser using Blob and URL.createObjectURL. All recent browsers support this.

You can not directly save the file you create, since that would cause massive security problems, but you can provide it as a download link for the user. You can suggest a file name via the download attribute of the link, in browsers that support the download attribute. As with any other download, the user downloading the file will have the final say on the file name though.

var textFile = null,
  makeTextFile = function (text) {
    var data = new Blob([text], {type: 'text/plain'});

    // If we are replacing a previously generated file we need to
    // manually revoke the object URL to avoid memory leaks.
    if (textFile !== null) {
      window.URL.revokeObjectURL(textFile);
    }

    textFile = window.URL.createObjectURL(data);

    // returns a URL you can use as a href
    return textFile;
  };

Here's an example that uses this technique to save arbitrary text from a textarea.

If you want to immediately initiate the download instead of requiring the user to click on a link, you can use mouse events to simulate a mouse click on the link as Lifecube's answer did. I've created an updated example that uses this technique.

  var create = document.getElementById('create'),
    textbox = document.getElementById('textbox');

  create.addEventListener('click', function () {
    var link = document.createElement('a');
    link.setAttribute('download', 'info.txt');
    link.href = makeTextFile(textbox.value);
    document.body.appendChild(link);

    // wait for the link to be added to the document
    window.requestAnimationFrame(function () {
      var event = new MouseEvent('click');
      link.dispatchEvent(event);
      document.body.removeChild(link);
    });

  }, false);
Forgo answered 9/1, 2014 at 9:23 Comment(10)
@FirstBlood What part isn't working, are you getting an error? The file and link creation should work in Safari 7+ (I believe that stuff should also work using in Safari 6 if you use the prefixed version of URL). Setting the file name will not work in Safari because it still hasn't implemented the download attribute.Forgo
I was trying it on Safari 5.1 :)Fustian
the new line character is missing from the saved docCleliaclellan
@Cleliaclellan the newline characters are there. JS uses the newline character \n to represent new lines like UNIX programs do. You are probably viewing it in a Windows program, such as Notepad, which does not render the \n character as a new line. If you want the newlines to be correctly rendered in Notepad and some other Windows programs, before putting the text into the Blob replace each \n with \r\n: text = text.replace(/\n/g, '\r\n').Forgo
While this sort of works.. your fiddle will not work on IE because IE does not support the download attribute.Scrutable
I was wondering how can we directly download. Eg- When user has clicked on a Download CSV, I am first creating a CSV and then I want to download immediately..Note, I don't want to keep the content ready in href link because the data I want to download is dynamic. So, If I follow your approach, it works, but I would have to click on button twice(to generate first and then download). How shall I do it?Cassondra
@user3241111 you could dispatch a mouse event to start the download as Lifecube did in his answer. I've created an updated fiddle that does this, I'll add it to the answer too.Forgo
That's a hack not a proper way! Isn't it? :PCassondra
@user3241111 Not really, it should work. Stuff like that is not all that unusual. I've seen hackyer ways of doing it ;-) In the past I've also got away with just generating the file on mouseover on the link, but depending on how much processing it is doing that might not work great.Forgo
You can start the download automatically just with link.click()Traverse
S
112

Some suggestions for this -

  1. If you are trying to write a file on client machine, You can't do this in any cross-browser way. IE does have methods to enable "trusted" applications to use ActiveX objects to read/write file.
  2. If you are trying to save it on your server then simply pass on the text data to your server and execute the file writing code using some server side language.
  3. To store some information on the client side that is considerably small, you can go for cookies.
  4. Using the HTML5 API for Local Storage.
Selfpropulsion answered 9/1, 2014 at 6:1 Comment(5)
HTML5 API is maxed at 5 mb only.Foghorn
Yes, you can not write into system file without select it. Read Official Docs: w3.org/TR/file-upload/#security-discussionColloidal
Can you explain point 2. "If you are trying to save it on your server then simply pass on the text data to your server and execute the file writing code using some server side language." Can You give any link tutorial?Fettle
@Fettle it's pretty self explanatory , given the text data (coming from client) create/append to a file on server side. i.e write the file code on the server side.Bibliotheca
Local storage is limited to only 5MB in most browsers, so I would use IndexedDB to store larger files.Stettin
A
52

If you are talking about browser javascript, you can not write data directly to local file for security reason. HTML 5 new API can only allow you to read files.

But if you want to write data, and enable user to download as a file to local. the following code works:

    function download(strData, strFileName, strMimeType) {
    var D = document,
        A = arguments,
        a = D.createElement("a"),
        d = A[0],
        n = A[1],
        t = A[2] || "text/plain";

    //build download link:
    a.href = "data:" + strMimeType + "charset=utf-8," + escape(strData);


    if (window.MSBlobBuilder) { // IE10
        var bb = new MSBlobBuilder();
        bb.append(strData);
        return navigator.msSaveBlob(bb, strFileName);
    } /* end if(window.MSBlobBuilder) */



    if ('download' in a) { //FF20, CH19
        a.setAttribute("download", n);
        a.innerHTML = "downloading...";
        D.body.appendChild(a);
        setTimeout(function() {
            var e = D.createEvent("MouseEvents");
            e.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
            a.dispatchEvent(e);
            D.body.removeChild(a);
        }, 66);
        return true;
    }; /* end if('download' in a) */



    //do iframe dataURL download: (older W3)
    var f = D.createElement("iframe");
    D.body.appendChild(f);
    f.src = "data:" + (A[2] ? A[2] : "application/octet-stream") + (window.btoa ? ";base64" : "") + "," + (window.btoa ? window.btoa : escape)(strData);
    setTimeout(function() {
        D.body.removeChild(f);
    }, 333);
    return true;
}

to use it:

download('the content of the file', 'filename.txt', 'text/plain');

Armure answered 9/1, 2014 at 6:11 Comment(6)
the above solution is kind of outdated. You may need to consider the html 5 javascript lib. github.com/eligrey/FileSaver.jsArmure
@Armure using FileSaver.js, is there a way to automatically save text to a file without user interaction? Thanks! New to JS; all your help is appreciatedAwakening
To several questions about saving a file without user knowing it: Such a behavior is just what is avoided by the design. That would open a Pandora's box of easy-to-use security threats. Cookies are for collecting data for marketing purposes.Zoi
Note I can't get this to download a html file as .html in firefox v76 on Windows 10. The download has .pdf appended to the end of it.Traceytrachea
Is just another developer being sarcastic?Heuristic
Not sure what's 'outdated' about this, seven years later it still worked perfectly fine for me in Brave. Cut, paste, enjoy.Bonnell
P
37

Try

let a = document.createElement('a');
a.href = "data:application/octet-stream,"+encodeURIComponent("My DATA");
a.download = 'abc.txt';
a.click();

If you want to download binary data look here

Update

2020.06.14 I upgrade Chrome to 83.0 and above SO snippet stop works (reason: sandbox security restrictions) - but JSFiddle version works - here

Pangenesis answered 21/4, 2019 at 16:5 Comment(0)
C
27

Above answer is useful but, I found code which helps you to download text file directly on button click. In this code you can also change filename as you wish. It's pure javascript function with HTML5. Works for me!

function saveTextAsFile()
{
    var textToWrite = document.getElementById("inputTextToSave").value;
    var textFileAsBlob = new Blob([textToWrite], {type:'text/plain'});
    var fileNameToSaveAs = document.getElementById("inputFileNameToSaveAs").value;
      var downloadLink = document.createElement("a");
    downloadLink.download = fileNameToSaveAs;
    downloadLink.innerHTML = "Download File";
    if (window.webkitURL != null)
    {
        // Chrome allows the link to be clicked
        // without actually adding it to the DOM.
        downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
    }
    else
    {
        // Firefox requires the link to be added to the DOM
        // before it can be clicked.
        downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
        downloadLink.onclick = destroyClickedElement;
        downloadLink.style.display = "none";
        document.body.appendChild(downloadLink);
    }

    downloadLink.click();
}
Chil answered 30/9, 2015 at 5:25 Comment(3)
Excellent. Works for me on Opera. Except need to replace the unknown function: "destroyClickedElement" by the statement "document.body.removeChild(event.target)"Thomasenathomasin
You need to be careful when using createObjectURL. Unlike most things in JS, the objects you create with it are not automatically garbage collected when there are no more references to them; they are only garbage collected when the page closes. Since you are not using URL.revokeObjectURL() in this code to free the memory used by the last call, you have a memory leak; if the user calls saveTextFile multiple times, they will continue to consume more and more memory because you never released it.Forgo
Hello, I'm not a web developer, so, first thanks for your code, it looks great, but I doesn't work for me. I've tried to add <form onsubmit="saveTextAsFile()"> then my form, and I've changed downloadLink.download = "/home/myuser/myfile.txt", but it doesn't create anything. Any help? ThanksAncestress
P
13
const data = {name: 'Ronn', age: 27};              //sample json
const a = document.createElement('a');
const blob = new Blob([JSON.stringify(data)]);
a.href = URL.createObjectURL(blob);
a.download = 'sample-profile';                     //filename to download
a.click();

Check Blob documentation here - Blob MDN to provide extra parameters for file type. By default it will make .txt file

Poltroon answered 11/8, 2020 at 20:31 Comment(0)
B
9

In the case it is not possibile to use the new Blob solution, that is for sure the best solution in modern browser, it is still possible to use this simpler approach, that has a limit in the file size by the way:

function download() {
                var fileContents=JSON.stringify(jsonObject, null, 2);
                var fileName= "data.json";

                var pp = document.createElement('a');
                pp.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(fileContents));
                pp.setAttribute('download', fileName);
                pp.click();
            }
            setTimeout(function() {download()}, 500);

$('#download').on("click", function() {
  function download() {
    var jsonObject = {
      "name": "John",
      "age": 31,
      "city": "New York"
    };
    var fileContents = JSON.stringify(jsonObject, null, 2);
    var fileName = "data.json";

    var pp = document.createElement('a');
    pp.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(fileContents));
    pp.setAttribute('download', fileName);
    pp.click();
  }
  setTimeout(function() {
    download()
  }, 500);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="download">Download me</button>
Blanton answered 19/4, 2018 at 14:56 Comment(0)
E
4

Use the code by the user @useless-code above (https://mcmap.net/q/100059/-is-it-possible-to-write-data-to-file-using-only-javascript) to generate the file. If you want to download the file automatically, pass the textFile that was just generated to this function:

var downloadFile = function downloadURL(url) {
    var hiddenIFrameID = 'hiddenDownloader',
    iframe = document.getElementById(hiddenIFrameID);
    if (iframe === null) {
        iframe = document.createElement('iframe');
        iframe.id = hiddenIFrameID;
        iframe.style.display = 'none';
        document.body.appendChild(iframe);
    }
    iframe.src = url;
}
Exarate answered 19/2, 2015 at 19:43 Comment(3)
Dont know why this got a down vote. It works for me. People who down vote should at least leave a comment as to why this was down voted !Exarate
I didn't downvote, but actually commenting on voting is directly discouraged. User should comment on the content of a post, and vote on the content of a post, but they should not comment on their votes. If someone votes without commenting you can take it to mean "this answer is useful" or "this answer is not useful" depending on the vote cast.Ytterbia
This is not working.. It doesn't download the file. It just creates an iframe which is hidden. I tested on chrome & firefoxUnshaped
H
3

I found good answers here, but also found a simpler way.

The button to create the blob and the download link can be combined in one link, as the link element can have an onclick attribute. (The reverse seems not possible, adding a href to a button does not work.)

You can style the link as a button using bootstrap, which is still pure javascript, except for styling.

Combining the button and the download link also reduces code, as fewer of those ugly getElementById calls are needed.

This example needs only one button click to create the text-blob and download it:

<a id="a_btn_writetofile" download="info.txt" href="#" class="btn btn-primary" 
   onclick="exportFile('This is some dummy data.\nAnd some more dummy data.\n', 'a_btn_writetofile')"
>
   Write To File
</a>

<script>
    // URL pointing to the Blob with the file contents
    var objUrl = null;
    // create the blob with file content, and attach the URL to the downloadlink; 
    // NB: link must have the download attribute
    // this method can go to your library
    function exportFile(fileContent, downloadLinkId) {
        // revoke the old object URL to avoid memory leaks.
        if (objUrl !== null) {
            window.URL.revokeObjectURL(objUrl);
        }
        // create the object that contains the file data and that can be referred to with a URL
        var data = new Blob([fileContent], { type: 'text/plain' });
        objUrl = window.URL.createObjectURL(data);
        // attach the object to the download link (styled as button)
        var downloadLinkButton = document.getElementById(downloadLinkId);
        downloadLinkButton.href = objUrl;
    };
</script>
Hyperkinesia answered 12/7, 2018 at 11:56 Comment(3)
blocked by kaspersky :(Varner
@Varner Security uber alles, but do you also know why it is blocked?Hyperkinesia
my guess would be preventing unwanted files to be downloaded without user action.Varner
B
3

This is the top result in Google for "js how to write to local file" so it warrants a newer answer in light of new APIs being added in 2023 (and is available in shipping browsers like Chrome).

In a 'secure context', a webpage can now ask for access to a directory or local file. When you ask for access to a directory, the user is prompted by the browser to accept or reject the request.

Once they have accepted your request, you have access to the directory and all sub-directories. At this point, you can ask for write access. (It is up for the browser to interpret that request.)

// open a directory picker and wait for the user to pick a file
const directory = await showDirectoryPicker();

// list the files in the directory
for await (const fileEntity of directory.values()) {
    if (fileEntity.kind === "file") {
        console.log(fileEntity.name);
    }
}

For a given FileSystemFileHandle you can turn it into a FileSystemWritableFileStream by calling createWritable. In Chrome, the first call to createWritable prompts the user to grant the code access to write to the local file..

// write a file (and implicitly ask for write permission)
const writable = await fileEntity.createWritable();
await writable.write("Hello!");
await writable.close();

All modern browsers seem to support this API apart from Safari, which does not support createWritable.

Blackwood answered 9/9, 2023 at 22:18 Comment(1)
I love this API but unfortunately, this is only available in a small parts of modern browsers, so one should not use this without a fallback, which then becomes a pretty long solution to implement. So please, if you want to create cross-browser solution, think twice.Countercurrent
M
0

Here is a single-page local-file version for use when you need the extra processing functionality of a scripting language.

  1. Save the code below to a text file
  2. Change the file extension from '.txt' to '.html'
  3. Right-click > Open With... > notepad
  4. Program word processing as needed, then save
  5. Double-click html file to open in default browser
  6. Result will be previewed in the black box, click download to get the resulting text file

Code:

<!DOCTYPE HTML>
<HTML>
<HEAD>
</HEAD>
<BODY>
<SCRIPT>
    // do text manipulation here
    let string1 = 'test\r\n';
    let string2 = 'export.';
    
    // assemble final string
    const finalText = string1 + string2;
    
    // convert to blob
    const data = new Blob([finalText], {type: 'text/plain'});
    
    // create file link
    const link = document.createElement('a');
    link.innerHTML = 'download';
    link.setAttribute('download', 'data.txt');
    link.href = window.URL.createObjectURL(data);
    document.body.appendChild(link);
    
    // preview the output in a paragraph
    const htmlBreak = string => {
        return string.replace(/(?:\r\n|\r|\n)/g, '<br>');
    }
    const preview = document.createElement('p');
    preview.innerHTML = htmlBreak(finalText);
    preview.style.border = "1px solid black";
    document.body.appendChild(preview);
</SCRIPT>
</BODY>
</HTML>
Mannino answered 31/7, 2022 at 22:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.