Getting to Grips with the HTML5 File API

The HTML5 File API allows developers to interact with the local filesystem on the client-side. Using these APIs, developers can build more robust web applications that work seamlessly both online and offline. This tutorial demonstrates the basic usage of these APIs to do common tasks like reading the properties and content of files.

Disclaimer – At the time of writing this article, only the latest versions of Chrome, Firefox and Opera support these features.

1. Feature Detection – Check if the browser supports HTML5 File API

Before we proceed, it is important to check if the browser supports the following file APIs:

  • File – Provides read-only information such as name, type, size and last modified date.
  • FileList – Contains the list of all file objects, when handling selection of mulitple files.
  • FileReader – Object to read the file.
if (window.File && window.FileList && window.FileReader) 
{
    /************************************ 
     * All the File APIs are supported. * 
     * Entire code goes here.           *
     ************************************/
} 
else 
{
    alert('Sorry! you're browser does not support HTML5 File APIs.');
}

2. Handle selection of a single file.

The easiest way to load a file is to use a standard method, which allows the selection of a single file only:

<input type="file" id="file" name="file">

Try it:

3. Handle a selection of multiple files.

Simply add the multiple attribute to the input element. The name="files[]" variable stores the list of all selected files. This enables the user to select multiple files in one instance. Note, even though you can select the folders in the dialog box, the browser will ignore them when processing.

<input type="file" id="files" name="files[]" multiple>

Try it:

4. List all of the selected files and their attributes.

The simplest way to implement this, is to attach a listener to the input element and call a function which will attempt to read the properties of each file selected:

function listFileProperties(event) 
{
    /* Read the list of the selected files. */
    var files = event.target.files; 

    /* Read each file and list down the properties in a table. */
    var output = "<table><tr><td>Filename</td><td>File Type</td><td>File Size</td><td>Last Modified Date</td></tr>";

    for (var i = 0, f; f = files[i]; i++) 
    {
        output += "<tr><td>" + escape(f.name) + "</td>";       /* f.name - Filename  */
        output += "<td>" + f.type  + "</td>";                  /* f.type - File Type */
        output += "<td>" + f.size + " bytes</td>";             /* f.size - File Size */
        output += "<td>" + f.lastModifiedDate + "</td></tr>";  /* f.lastModifiedDate - Last Modified Date */
    }
    
    output += "</table>";
    document.getElementById('list').innerHTML = output;   
}

/* Listener for single file input element. */
document.getElementById('file').addEventListener('change', listFileProperties, false);

/* Listener for multiple files input element. */
document.getElementById('files').addEventListener('change', listFileProperties, false);

Try the demo.

5. Drag and Drop mulitple files.

We first create a division as a drop zone where the files will be dropped. Then we attach listeners to both the events – ‘dragover’ and ‘drop’. For the ‘drop’ event we call the function which attempts to read the file properties. The rest of the code, pretty much remains the same.

<div id="drop_zone">Drop files here</div>
<output id="list"></output>

<script>

function handleDragOver(event) 
{
    event.stopPropagation();
    event.preventDefault();
    event.dataTransfer.dropEffect = 'copy';
}

function handleDnDFileSelect(event) 
{    
    event.stopPropagation();
    event.preventDefault();

    /* Read the list of the selected files. */
    var files = event.dataTransfer.files;
    
    /* Read each file and list down the properties in a table. */
    var output = "<table><tr><td>Filename</td><td>File Type</td><td>File Size</td><td>Last Modified Date</td></tr>";

    for (var i = 0, f; f = files[i]; i++) 
    {
        output += "<tr><td>" + escape(f.name) + "</td>";       /* f.name - Filename  */
        output += "<td>" + f.type  + "</td>";                  /* f.type - File Type */
        output += "<td>" + f.size + " bytes</td>";             /* f.size - File Size */
        output += "<td>" + f.lastModifiedDate + "</td></tr>";  /* f.lastModifiedDate - Last Modified Date */
    }
    
    output += "</table>";
    document.getElementById('list').innerHTML = output;   
}

/* Setup the Drag-n-Drop listeners. */
var dropZone = document.getElementById('drop_zone');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleDnDFileSelect, false);

</script>

Try the demo.

6. Read a file.

Instantiate the FileReader object, using new FileReader() to read the contents into memory. When the load finishes, the reader’s onload event is fired and its result attribute can be used to access the file data.

<button id="readFile">Read File</button>
<output id="content"></output>
    
<script>
    
function readFile() 
{
    /* Get the reference of the inpout element. */
    var files = document.getElementById('files').files;

    if (!files.length) 
    {
      alert('Please select a file!');
      return;
    }
    
    /* Reading the first file selected. You can process other files similarly in loop. */
    var file = files[0];

    /* Instantiate the File Reader object. */
    var reader = new FileReader();

    /* onLoad event is fired when the load completes. */
    reader.onload = function(event) {
        document.getElementById('content').textContent = event.target.result;      
    };

    /* The readAsText method will read the file's data as a text string. By default the string is decoded as 'UTF-8'. */
    reader.readAsText(file);
}
     
document.getElementById('readFile').addEventListener('click', function(event) {
      readFile();    
  }, false);

</script>

Try the demo.

Conclusion:

This API can be extended to implement client-side logic to verify the mime-type of the uploaded file, restrict the size of an upload, create a thumbnail preview of images as they’re being sent to the server or allow an app to save a file reference while the user is offline.

When used in conjunction with the above data structures, the FileReader interface can be used to asynchronously read a file through familiar JavaScript event handling and monitor the progress of a read process, catch errors, and determine when the load is complete.

Author: (1 Posts)

Pankaj Parashar is a front-end designer and web developer from Mumbai, India. He is extremely passionate about the web, constantly looking for new web technologies and aims to make the web a better place to live. He specializes in frontend technologies like HTML5, CSS3, jQuery and knows a thing or two about design as well! He also writes for txpmag.com/people/pankaj-parasha and you can find him on pankajparashar.com and follow his updates@pankajparashar.

Comments