FileSystem API in HTML5 - Working with Files in the browser

Sheonarayan
Posted by in HTML 5 category on for Advance level | Points: 250 | Views : 28448 red flag
Rating: 5 out of 5  
 2 vote(s)

In this article, we are going to learn how to create, update, delete a file in the browser using FileSystem API in HTML5.


 Download source code for FileSystem API in HTML5 - Working with Files in the browser

Recommendation
Read Google tips and tricks to improve productivity before this article.

Introduction


Can you imagine, a web application giving ability to create, update, delete and rename a file in the browser? Yes, you can do all this now in the browser using FileSystem API in HTML 5 supported browser.

All files that we create in browser gets stored in sandboxed section of the user's local file system. At the time of writing this article, Google Chrome and Opera supports this feature. Surprisingly, FireFox and Internet Explorer doesn't.

Also note that file created in one browser is not accessible from another browser on the same machine. File can be created either temporarily or permanently using below option
  • window.PERSISTENT - creates a permanent file that can only be deleted by user explicitly
  • window.TEMPORARY - creates a temporary file that gets deleted at browser discretion (when it needs some space) or when user closes the browser.

Prerequisite


Intermediate level knowledge of JavaScript is a must to understand this article.

User interface used to demonstrate FileSytem API features


To demonstrate working with FileSystem API, we have created below form. Where we have following
  1. a file name text box
  2. rename text box 
  3. content for the file text box
  4. Rename button
  5. Save button (Folders link that we will discuss in the next article)
  6. List of files section that list all the files created by this user



Setting up the environment


Let's setup the environment first. To do that we have tried to set the requestFileSystem value to the object that is available in the browser for FileSystem (depending on which browser is being used by the user).

           // get the fs object based on Browser being used
            window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;

            // Get the page elements to work with
            var maxFileSizeQuota = 1024 * 1024 * 5;
            var form = document.getElementById('form1');
            var fileNameTextBox = document.getElementById('txtFileName');
            var contentTextArea = document.getElementById('txtFileContent');
            var fileList = document.getElementById('listOfFiles');
            var messageBox = document.getElementById('lblMessages');


            // global variable to store the fs object
            var fs = null;
Variables created and its use in the above code snippet are following
  1. maxFileSizeQuota - how big size we want to allocate to store user file. It is specified in bytes.
  2. form - the form element on the page
  3. fileNameTextBox - the file name text box reference
  4. contentTextArea - content text box reference
  5. fileList - the reference of the div that will list users file
  6. messageBox - the reference of the div that shows the success or failure message
  7. fs - a page level variable that holds the reference of the FileSystem object to be used through out the page

At the last of the script block (place just before </body>) we will write following code snippet (alternatively, all script mentioned in this article can be kept inside window.load event).

       // initialize the file System
            function initFileSystem() {
                navigator.webkitPersistentStorage.requestQuota(maxFileSizeQuota, function (grantedSize) {
                    window.requestFileSystem(window.PERSISTENT, grantedSize, function (fileSystem) {
                        fs = fileSystem;

                        form.addEventListener('submit', function (e) {
                            e.preventDefault();

                            // save the file now
                            saveTheFile(fileNameTextBox.value, contentTextArea.value);
                        });

                        // List the file now
                        listFiles();

                    }, handleError);
                }, handleError);
            }

            // Start the application
            if (window.requestFileSystem) {
                initFileSystem();
            } else {
                alert('Sorry! Your browser doesn\'t support the FileSystem API :(');
            }
When the page loads, it checks for window.requestFileSystem object, if it exists calls initFileSystem() function otherwise shows alert that the browser doesn't support FileSystem.

In the initFileSystem() function, we are requesting the quota from the browser for the files we are going to create by passing the maxFileSizeQuota variable.

The requestQuota function has following parameters
  1. maxFileSizeQuota - the size on the disk to allocate for files
  2. success call back function to execute when request is successful, it accepts the size granted for the file to be created as parameter
  3. failure call back function to execute when request is not successful (handleError - explained in the last of this article)
In the success call back function, we call the requestFileSystem function that accepts following parameter
  1. type of file to create - Peristent or Temporary (explained above)
  2. max file size
  3. success call back function
  4. failure call back function
Under this function, we are setting the value of fs page level variable declared; that is nothing but the returned object when the File System request is successful.

Then we are attaching a submit event to the form and calling saveTheFile function by passing the file name and content to save as parameter. Once the file is created, we are calling listFiles() function that lists all files and folders created by this user.

Creating / Saving a file using FileSystem in browser


This method accepts file name and content as parameter and call getFile function that accepts file name as parameter and create (true - creates the file; false - read the content of the file). The third parameter is the success call back function and fourth is failure call back function.
         // Save a file in the FileSystem.
            function saveTheFile(filename, content) {
                fs.root.getFile(filename, { create: true }, function (fileEntry) {

                    fileEntry.createWriter(function (fileWriter) {

                        fileWriter.onwriteend = function (e) {
                            // Update the file browser.
                            listFiles();

                            // Clean out the form field.
                            fileNameTextBox.value = '';
                            contentTextArea.value = '';

                            // Show message
                            messageBox.innerHTML = 'File saved successfully!';
                        };

                        fileWriter.onerror = function (e) {
                            alert('Error occured: ' + e.toString() + "\n File couldn't saved");
                        };

                        var contentBlob = new Blob([content], { type: 'text/plain' });

                        fileWriter.write(contentBlob);

                    }, handleError);

                }, handleError);
            }

In the success call back function, we are calling createWriter function  in which we are setting a function on onwritend event (this fires when the file write is complete). In this function, we are calling listFiles() function, resetting the values of text boxes and showing success alert.

If any error occurs, we are showing an alert with the error message.

Then we are creating a Blob (used to save the content using FileSyste API in JavaScript) that accepts the content to save and type of content as parameter. Finally, we are calling write method on fileWriter object that actually writes the content in the file.

Listing files using FileSystem API in the browser


This function creates a reader object by instantiating createReader() object. Create an array and then creates a function called fetchEntries that read the file/folder entries. 
        function listFiles() {
                var dirReader = fs.root.createReader();
                var entries = [];

                function fetchEntries() {
                    dirReader.readEntries(function (results) {
                        if (!results.length) {
                            displayEntries(entries.sort().reverse());
                        } else {
                            entries = entries.concat(results);
                            fetchEntries();
                        }
                    }, handleError);
                };

                fetchEntries();
            }
In this function, we are calling displayEntries function by passing the the list of files  (as an array) as parameter. Note that displayEntires function creates necessary list item that will enable us to bring the file into edit mode or delete the file.

readEntries function doesn't guarantee that in a single call all the files and folders will be returns so we have to call it multiple times till the results are found; this is the reason we are calling fetchEntires function recursively.

displayEntires function looks like below

            function displayEntries(entries) {
                // Clear out the current file browser entries.
                fileList.innerHTML = '';

                entries.forEach(function (entry, i) {

                    // create edit button
                    var li = document.createElement('li');
                    var button = document.createElement('button');
                    button.innerHTML = 'Show content of <b>' + entry.fullPath + '</b> file';
                    li.appendChild(button);

                    // create delete link
                    var delLink = document.createElement('a');
                    delLink.innerHTML = ' <span style="color:red;cursor:pointer;">[x]</span>';
                    li.appendChild(delLink);

                    // append both of them
                    fileList.appendChild(li);

                    // add click event on the button
                    button.addEventListener('click', function (e) {
                        e.preventDefault();
                        loadTheFile(entry.name);
                    });

                    // add click even on the link
                    delLink.addEventListener('click', function (e) {
                        e.preventDefault();
                        deleteTheFile(entry.name);
                    });
                });
            }
The above function accepts the entries (list of files and folders), set the fileList to empty so that fresh list can be added.

It loops through each entry of the results (array of files and folders) and create an item to the list. While creating the item, it also sets necessary event that enables us to load the file content and delete the file content.

Reading file content using FileSystem API in the browser


This function receives the file name when the button is clicked on each item added from displayEntries function.
        function loadTheFile(filename) {
                // 2nd parameter is whether to create the file or read the file, refer to deleteTheFile function
                fs.root.getFile(filename, {}, function (fileEntry) {

                    fileEntry.file(function (file) {
                        var reader = new FileReader();

                        reader.onload = function (e) {
                            // Update the form fields.
                            fileNameTextBox.value = filename;
                            contentTextArea.value = this.result;
                        };

                        reader.readAsText(file);
                    }, handleError);

                }, handleError);
            }
In the above function, we are instantiating the FileReader object and assigning onload event to it. In this event, we are setting the file name and file content to the respective text boxes.

onload event fires only when we call the reader.readAsText function.

Deleting files using FileSystem API in the browser


This function accepts file name as parameter and calls the getFile function. The 3rd parameter (success call back function) provides the fileEntry object calls the remove function and the file is removed. In the remove method we are calling listFiles() function that will list fresh files exists in the users machine.

       function deleteTheFile(filename) {
                fs.root.getFile(filename, { create: false }, function (fileEntry) {

                    fileEntry.remove(function (e) {
                        // Update the file list.
                        listFiles();

                        // Show delete message
                        messageBox.innerHTML = 'File deleted!';
                    }, handleError);

                }, handleError);
            }

Renaming file using FileSystem API in the browser


There is no function called Rename in the FileSystem API, so we just need to move the file with different name.
           // Rename the file
            function RenameTheFile()
            {
                var renameTextBox = document.getElementById('txtRename');

                fs.root.getFile(fileNameTextBox.value, {}, function (fileEntry) {
                    fileEntry.moveTo(fs.root, renameTextBox.value);

                    listFiles(); // relist the files

                    alert("The file has been renamed successfully !.");

                }, handleError);
            }
In the above function, we get the file name to be renamed and the new file name. We call the getFile() function that accepts existing file name, (2nd parameter is not needed), and success call back function. In this, we are calling moveTo function that moves the existing file with different name to the current location.

Handling error using FileSystem API in the browser


Below function is a generic function that based on the error code returned by the FileSystem API, shows the error in alert.
            // Generic Error handler used in the FileSyste that is found on the web
            function handleError(error) {
                var message = '';

                switch (error.code) {
                    case FileError.SECURITY_ERR:
                        message = 'Security Error occured';
                        break;
                    case FileError.NOT_FOUND_ERR:
                        message = 'File Not Found';
                        break;
                    case FileError.QUOTA_EXCEEDED_ERR:
                        message = 'Quota limit Exceeded';
                        break;
                    case FileError.INVALID_MODIFICATION_ERR:
                        message = "Can''t modify";
                        break;
                    case FileError.INVALID_STATE_ERR:
                        message = 'Invalid State';
                        break;
                    default:
                        message = 'Do not know, what happened. Report to webmaster';
                        break;
                }
                alert(message);
            }

How to test?


  1. Write the file name in the textbox and content you want to save into the Content box and click on the Save button, we should get a success alert and that file should be listed under "List of files created".
  2. Click on the button of the list item and the same file should get loaded into the Edit mode. Modifying and clicking on the Save button should save the file with updated content.
  3. Click on the Delete  (x) link and the file should get deleted.
  4. Bring the file into Edit mode by clicking on the respective button from the List of files and write another name into "rename this file" text box and click on the Rename button. Refresh the browser again and you should be able to see the file name change.

What next ? In the next article, we are going to learn working with folders using FileSystem API in HTML 5, till then happy learning.

Hope this entire effort will be useful. The entire source code can be downloaded from top of the article.

Thanks for reading and if you are looking for online training of HTML5, CSS3, MVC etc, visit http://www.itfunda.com

Conclusion


In this article, we learned how to create a file, update a file, rename a file, and delete a file using FileSystem API in the browser. For any question or clarification, please respond to this article.
Page copy protected against web site content infringement by Copyscape

About the Author

Sheonarayan
Full Name: Sheo Narayan
Member Level: HonoraryPlatinum
Member Status: Administrator
Member Since: 7/8/2008 6:32:14 PM
Country: India
Regards, Sheo Narayan http://www.dotnetfunda.com

Ex-Microsoft MVP, Author, Writer, Mentor & architecting applications since year 2001. Connect me on http://www.facebook.com/sheo.narayan | https://twitter.com/sheonarayan | http://www.linkedin.com/in/sheonarayan

Login to vote for this post.

Comments or Responses

Login to post response

Comment using Facebook(Author doesn't get notification)