Frontend DevelopmentJavascript

Introduction To Javascript File Api

HTML5 released a standard way to interact with local files, via the File API specification. As example of its capabilities, the File API could be used to 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. Additionally, you could use client-side logic to verify an upload’s mimetype matches its file extension or restrict the size of an upload.

 

The new Api provides several interfaces for accessing files from a ‘local’ filesystem:

  1. File – an individual file; provides readonly information such as name, file size, mimetype, and a reference to the file handle.
  2. FileList – an array-like sequence of File objects. (Think <input type="file" multiple> or dragging a directory of files from the desktop).
  3. Blob – Allows for slicing a file into byte ranges.

 

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. Thus, it is possible to monitor the progress of a read, catch errors, and determine when a load is complete. In many ways the APIs resemble XMLHttpRequest‘s event model.

 

Selecting files

The first thing to do is check that your browser fully supports the File API:

// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) {
  // Great success! All the File APIs are supported.
} else {
  alert('The File APIs are not fully supported in this browser.');
}

Using form input for selecting

The most straightforward way to load a file is to use a standard <input type="file"> element. JavaScript returns the list of selected File objects as a FileList. Here’s an example that uses the ‘multiple’ attribute to allow selecting several files at once:

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

<script>
  function handleFileSelect(evt) {
    var files = evt.target.files; // FileList object

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
      output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
                  '</li>');
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

Using drag and drop for selecting

Another technique for loading files is native drag and drop from the desktop to the browser. We can modify the previous example slightly to include drag and drop support.

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

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

    var files = evt.dataTransfer.files; // FileList object.

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
      output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
                  '</li>');
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }

  function handleDragOver(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
  }

  // Setup the dnd listeners.
  var dropZone = document.getElementById('drop_zone');
  dropZone.addEventListener('dragover', handleDragOver, false);
  dropZone.addEventListener('drop', handleFileSelect, false);
</script>

Reading files

After you’ve obtained a File reference, instantiate a FileReader object to read its 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.

FileReader includes four options for reading a file, asynchronously:

  • FileReader.readAsBinaryString(Blob|File) – The result property will contain the file/blob’s data as a binary string. Every byte is represented by an integer in the range [0..255].
  • FileReader.readAsText(Blob|File, opt_encoding) – The result property will contain the file/blob’s data as a text string. By default the string is decoded as ‘UTF-8’. Use the optional encoding parameter can specify a different format.
  • FileReader.readAsDataURL(Blob|File) – The result property will contain the file/blob’s data encoded as a data URL.
  • FileReader.readAsArrayBuffer(Blob|File) – The result property will contain the file/blob’s data as an ArrayBuffer object.

Once one of these read methods is called on your FileReader object, the onloadstart, onprogress, onload, onabort, onerror, and onloadend can be used to track its progress.

The example below filters out images from the user’s selection, calls reader.readAsDataURL() on the file, and renders a thumbnail by setting the ‘src’ attribute to a data URL.

<style>
  .thumb {
    height: 75px;
    border: 1px solid #000;
    margin: 10px 5px 0 0;
  }
</style>

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

<script>
  function handleFileSelect(evt) {
    var files = evt.target.files; // FileList object

    // Loop through the FileList and render image files as thumbnails.
    for (var i = 0, f; f = files[i]; i++) {

      // Only process image files.
      if (!f.type.match('image.*')) {
        continue;
      }

      var reader = new FileReader();

      // Closure to capture the file information.
      reader.onload = (function(theFile) {
        return function(e) {
          // Render thumbnail.
          var span = document.createElement('span');
          span.innerHTML = ['<img class="thumb" src="', e.target.result,
                            '" title="', escape(theFile.name), '"/>'].join('');
          document.getElementById('list').insertBefore(span, null);
        };
      })(f);

      // Read in the image file as a data URL.
      reader.readAsDataURL(f);
    }
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

Example: Showing thumbnails of user-selected images

<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
<label for="fileElem">Select some files</label>

<script>
function handleFiles(files) {
  for (var i = 0; i < files.length; i++) {
    var file = files[i];
    
    if (!file.type.startsWith('image/')){ continue }
    
    var img = document.createElement("img");
    img.classList.add("obj");
    img.file = file;
    preview.appendChild(img); // Assuming that "preview" is the div output where the content will be displayed.
    
    var reader = new FileReader();
    reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
    reader.readAsDataURL(file);
  }
}
</script>

Using object URLs

When you have a File object you’d like to reference by URL from HTML, you can create an object URL for it like this:

var objectURL = window.URL.createObjectURL(fileObj);

The object URL is a string identifying the File object. Each time you call window.URL.createObjectURL(), a unique object URL is created even if you’ve created an object URL for that file already. Each of these must be released. While they are released automatically when the document is unloaded, if your page uses them dynamically you should release them explicitly by calling window.URL.revokeObjectURL():

window.URL.revokeObjectURL(objectURL);

Example: Using object URLs to display images

This example uses object URLs to display image thumbnails. In addition, it displays other file information including their names and sizes.

The HTML that presents the interface looks like this:

<input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)">
<a href="#" id="fileSelect">Select some files</a> 
<div id="fileList">
  <p>No files selected!</p>
</div>

This establishes our file <input> element as well as a link that invokes the file picker (since we keep the file input hidden to prevent that less-than-attractive user interface from being displayed). This is explained in the section Using hidden file input elements using the click() method, as is the method that invokes the file picker.

The handleFiles() method follows:

window.URL = window.URL || window.webkitURL;

var fileSelect = document.getElementById("fileSelect"),
    fileElem = document.getElementById("fileElem"),
    fileList = document.getElementById("fileList");

fileSelect.addEventListener("click", function (e) {
  if (fileElem) {
    fileElem.click();
  }
  e.preventDefault(); // prevent navigation to "#"
}, false);

function handleFiles(files) {
  if (!files.length) {
    fileList.innerHTML = "<p>No files selected!</p>";
  } else {
    fileList.innerHTML = "";
    var list = document.createElement("ul");
    fileList.appendChild(list);
    for (var i = 0; i < files.length; i++) {
      var li = document.createElement("li");
      list.appendChild(li);
      
      var img = document.createElement("img");
      img.src = window.URL.createObjectURL(files[i]);
      img.height = 60;
      img.onload = function() {
        window.URL.revokeObjectURL(this.src);
      }
      li.appendChild(img);
      var info = document.createElement("span");
      info.innerHTML = files[i].name + ": " + files[i].size + " bytes";
      li.appendChild(info);
    }
  }
}

 

0 0 vote
Article Rating

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
0

You may also like

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments