HTML5 File API

Jakob Jenkov
Last update: 2020-04-18

The HTML5 file API enables JavaScript inside HTML5 pages to load and process files from the local file system. Via the HTML5 file API it is possible for JavaScript to process a file locally, e.g. compress, encode or encrypt it, or upload the file in smaller chunks. Of course the HTML5 file API raises some security concerns. This HTML5 file API tutorial will explain both how to use the file API, and what the security constraints on the HTML5 file API are.

Core Objects of HTML5 File API

The HTML5 file API contains the following core objects:

  • FileList
  • File
  • Blob
  • FileReader

The File object represents a file in the local file system.

The FileList object represents a list of files in the local file system. For instance, a list of files inside a directory.

The Blob object represents a Binary Large OBject (BLOB) which is used to hold the contents of a single file from the local file system.

You will see how these file API objects are used in the following sections.

Selecting Files

Before the HTML5 file API can access a file from the local file system, the user has to select the file to give access to. For security reasons selecting files is done via the <input type="file"> HTML element. Here is an input element example:

<input type="file" >

By itself the input element is not enough. You need an onchange listener too. Here is how that looks:

<input type="file" onchange="readFiles(event)" >

The input element contains a browse button. When that button is clicked the user is shown a file dialog. In that file dialog the user can choose a file. The chosen file will be made available to the onchange listener via the event object passed as parameter to it.

Selecting Multiple Files

To enable the user to select multiple files, insert the multiple attribute into the input element. Here is how that looks:

<input type="file" onchange="readFiles(event)" multiple>

Selecting Files Via Drag and Drop

You can combine the HTML5 file API with the HTML5 drag and drop feature. By doing so the user can drag files from a file explorer on his / her computer (outside the browser) onto a "drop zone" HTML element inside the HTML page. The HTML page can detect when a file is dropped via JavaScript.

Here is a code example showing how to setup a drop zone HTML element so that you can detect when files are dragged onto it:


<div id="fileDropZone" >
    Drag file in here
</div>

<script>
    function drop(event) {
        evt.stopPropagation();
        evt.preventDefault();

        var fileList = event.dataTransfer.files;

        // access files via fileList
     }

    function dragOver(evt) {
        evt.stopPropagation();
        evt.preventDefault();
        evt.dataTransfer.dropEffect = 'copy';
    }

    var dropZone = document.getElementById("fileDropZone");
    dropZone.addEventListener("dragover", dragOver, false);
    dropZone.addEventListener("drop"    , drop    , false);
</script>

The two functions dragOver() and drop() are set as drag and drop event listeners on the drop zone HTML element (the div at the beginning of the example).

When a file is dropped onto the drop zone HTML element, the drop() function will be called. The list of files dragged onto the drop zone element can be found in the event.dataTransfer.files object (a FileList object).

The dragOver() function is not strictly necessary. It just shows that the file being dragged is copied. This is shown via the dragged file icon.

The rest of the code needed to access the selected files is the same as when selecting a file via the input element. You will see how that looks in the following sections.

It might be a good idea to style the drop zone HTML element to make it clear to the user that they can drag a file onto it, and where the borders of the drop zone are etc. I have left the styling out of the example above to make it shorter.

Accessing Selected Files

Once the user has selected one or more files, there are two ways to access the selected files.

The first way to access the selected files is by accessing the input field's files property. Here is an example of that:

var inputField = document.getElementById('theFileInput');
    
var selectedFiles = inputField.files;

for(var i=0; i<selectedFiles.length; i++) {
    var file = selectedFiles[i);    
}

The second way to access the selected files is via an onchange listener function on the input field. The selected files are accesible via the event object passed as parameter to the listener function. Here is an example showing both an input element and an onchange listener function:

<input type="file" onchange="readFiles(event)" multiple>

<script>
function readFiles(event) {
    var fileList = event.target.files;
}
</script>

The event.target.files object is a FileList object. It contains a list of the selected files as File objects. If only a single file is selected, this list contains only one object. Here is an example showing how to iterate the file list:

<input type="file" onchange="readFiles(event)" multiple>

<script>
function readFiles(event) {
    var fileList = event.target.files;

    for(var i=0; i < fileList.length; i++ ) {
        var file = fileList[i];     // a File object
        console.log("i: " + i + " - " + file.name);
    }
}
</script>

The FileList is a list of File objects. These File objects are used to access the files with. In the following sections you will see different ways to load the files via JavaScript.

Loading Files With a FileReader

Once the user has selected a file and you have a reference to the selected file (e.g. via the onchange event) you can read the file using a FileReader. The FileReader object contains the following functions you can use to load files with:

  • readAsText()
  • readAsDataUrl()
  • readAsArrayBuffer()

Each of these four functions take either a File object or a Blob object as parameter.

A File object can be obtained from a FileList object, as explained earlier.

A Blob object represents a part (or whole) of a file. You create a Blob object from a File object like this:

var theFile = fileList[0]; // a File from a FileList

var from = 3;
var to   = 9;
var blob = theFile.slice(from, to);   // create Blob

The from index represents the index of the first byte in the file to include in the Blob. the to index represents the index of the first byte that will not be included in the Blob. Thus, if the to index is 9 as in the example above, the byte with index 8 is the last byte to be included in the Blob .

Creating a FileReader

To use a FileReader you must first create a FileReader object. Here is how you create a FileReader object:

var reader = new FileReader();

Once the FileReader has been created you can call the various read functions on it.

Loading a File as Text

In order to load a file as text you use a FileReader object which is part of the HTML5 file API. Here is how loading a file via a FileReader looks:

<input type="file" onchange="readFiles(event)" multiple>

<script>
function readFiles(event) {
    var fileList = event.target.files;

    for(var i=0; i < fileList.length; i++ ) {
        loadAsText(fileList[i]);
    }
}

function loadAsText(theFile) {
    var reader = new FileReader();

    reader.onload = function(loadedEvent) {
        // result contains loaded file.
        console.log(loadedEvent.target.result);
    }
    reader.readAsText(theFile);
}
</script>

The file is loaded inside the loadAsText() function. First a FileReader object is created.

Second, an onload event handler function is set on the FileReader object. This event handler function is called when the file is finished loading.

Third, the readAsText() function on the FileReader is called with the File as parameter. This starts the loading of the file. When loading the file finishes, the onload event handler is called.

Loading a File as Text Slice

Instead of loading the whole file as text you can load a slice of the text instead. Here is an example function called loadAsTextSlice() which shows how to use the HTML5 file API to load a file as a text slice:

function loadAsTextSlice(theFile) {
    var start = 3;
    var stop  = 9;
    var blob = theFile.slice(start, stop);

    var reader = new FileReader();
    reader.onload = function(loadedEvent) {
        console.log(loadedEvent.target.result);
    }
    reader.readAsText(blob);
}

First the example creates a Blob object via the File object's slice() function. Second, a FileReader is created and an onload handler is set on the FileReader instance.

Third, the FileReader's readAsText() function is called with the Blob object as parameter. This starts the reading of the file. Once the file slice is read the onload event handler function is called. The text slice from the file is available in the loadedEvent.target.result variable.

Loading a File as Data URL

It is also possible to load a file as a data URL. A data URL can be set as source (src) on img elements with JavaScript. Here is a JavaScript function named loadAsUrl() that shows how to load a file as a data URL using the HTML5 file API:

function loadAsUrl(theFile) {
    var reader = new FileReader();

    reader.onload = function(loadedEvent) {
        var image = document.getElementById("theImage");
        image.setAttribute("src", loadedEvent.target.result);
    }

    reader.readAsDataURL(theFile);
}

First a FileReader is created. Second, an onload event handler is set on the FileReader. Third, the readAsDataURL() function is called on the FileReader. When the file has finished loading the onload event handler function will get called. The event.target.result property of the event object passed as parameter to the onload event handler function contains the file encoded as a data URL. You can now set the loaded and encoded file as src attribute value of the img element you want to show the image.

Load a File as ArrayBuffer

The readAsArrayBuffer() function of the FileReader object can be used to read a file as an ArrayBuffer. An ArrayBuffer represents an arbitrary length buffer of data. You cannot directly manipulate the data in the ArrayBuffer. Instead you have to create a DataView object which can access the data in the ArrayBuffer as different types, e.g as number of 8, 16 or 32 bits in size.

Here is an example of reading a file as an ArrayBuffer:

function loadAsUrl(theFile) {
    var reader = new FileReader();

    reader.onload = function(loadedEvent) {
        var arrayBuffer =  loadedEvent.target.result;
        var dataView = new DataView(arrayBuffer, 0, arrayBuffer.byteLength);

        var byte = dataView.getUint8(0);   //gets first byte of ArrayBuffer

        //... process rest of dataView ...
    }

    reader.readAsArrayBuffer(theFile);
}

Here you can read more about the DataView object .

Upload File via Fetch

It is possible to upload a file accessed via the HTML5 File API via the JavaScript AJAX fetch() function. Here is an example of how uploading a file via fetch() looks:

<form id="theForm">
    <input type="file" id="fileField" >
    <input type="button" value="Upload" onclick="upload(event)">


</form>

<script>
function upload(event) {
    console.log("Uploading...");

    const fileField = document.getElementById("fileField");
    const formData = new FormData();

    formData.append('test', 'testValue');
    formData.append('selectedFile', fileField.files[0]);

    fetch('https://mydomain/upload', {
        method: 'PUT',
        body: formData
    })
    .then((result) => {
        console.log('Success:', result);
    })
    ;
}
</script>

Monitoring Progress of File Loading

The HTML5 file API also enables you to monitor the progress of file loading, meaning you can be notified about how much of the file has been loaded. To be notified you need to set an onprogress listener function on the FileReader instance

var reader = new FileReader();

reader.onprogress = function(progressEvent) {

    if(progressEvent.lengthComputable) {
        var percentLoaded = Math.round( (
                progressEvent.loaded * 100) / progressEvent.total );
    }
    console.log("total: " + progressEvent.total + ", loaded: "
              + progressEvent.loaded + "(" + percentLoaded + "%)");
}

The progress event objects passed to the progress listener function contains a boolean property named lengthComputable. If this property has the value true then you can compute how much of the total file has been loaded. How that is done is shown above.

Browser Support for HTML5 File API

According to caniuse.com the HTML5 file API is reasonably well supported in most browsers. A few browsers do not support the File constructor, but you don't need that.

Jakob Jenkov

Featured Videos

Java ConcurrentMap + ConcurrentHashMap

Java Generics

Java ForkJoinPool

P2P Networks Introduction

















Close TOC
All Tutorial Trails
All Trails
Table of contents (TOC) for this tutorial trail
Trail TOC
Table of contents (TOC) for this tutorial
Page TOC
Previous tutorial in this tutorial trail
Previous
Next tutorial in this tutorial trail
Next