File ▸ Open: An introduction to the File API

Cameron McCormack · @heycam

File ▸ Open An introduction to the File API

File API

  • http://www.w3.org/TR/FileAPI/
  • Allows a Web page access to files selected by the user
  • Works in conjunction with <input type=file>
  • Still a W3C Working Draft, but widely implemented and close to being finished

The basics

  • An HTMLInputElement has a .files property, a FileList
  • Each entry in <input>.files is a File object, providing access to information about the file
  • A change event is dispatched to the <input> when files are selected

The basics – demo

Select a file...
<input type=file onchange="showFilePreview(event.target)">
<pre>Select a file...</pre>
<script>
function showFilePreview(input) {
  document.querySelector("pre").textContent =
      input.files[0].name + ": " +
      input.files[0].size + " bytes";
}
</script>

What metadata is available?

  • .name – just the filename part, not the path
  • .size – file size in bytes
  • .lastModifiedDate – as a Date object
  • .type – a media type like “text/plain” or “image/jpeg”

Reading a file

  • To read the contents, create a FileReader object – async
  • Add a load event listener to it for when it is done
  • Call a read method on the FileReader passing in the File

Reading a file – demo

Select a file...
<input type=file onchange="showFileContents(event.target)">
<pre>Select a file...</pre>
<script>
function showFileContents(input) {
  var reader = new FileReader();
  reader.onload = function() {
    document.querySelector("pre").textContent = reader.result;
  };
  reader.readAsText(input.files[0], "UTF-8");
}
</script>

Reading a file as a data: URL

  • Rather than reading the data into a plain string, we can get a data: URL
  • Allows us to load a file and use it in an <img src>, <audio src>, background-image, ...

Reading a file as a data: URL – demo

<img> <input type=file onchange="showImage(event.target)">
<script>
function showImage(input) {
  var reader = new FileReader();
  reader.onload = function() {
    document.querySelector("img").src = reader.result;
  };
  reader.readAsDataURL(input.files[0]);
}
</script>

Reading a file as bytes

  • We can also read a file as an array of bytes!
  • FileReader.readAsArrayBuffer() will produce an ArrayBuffer
  • Wrap it with a typed array – Uint8Array – to access the bytes in the buffer

Reading a file as bytes – demo

Select a file...
function showFileBytes(input) {
  var reader = new FileReader();
  reader.onload = function() {
    var s = "", bytes = new Uint8Array(reader.result);
    for (var i = 0; i < Math.max(bytes.length, 48); i++)
      s += (bytes[i] < 16 ? "0" : "") + bytes[i].toString(16) + " ";
    document.querySelector("pre").textContent = s + "..";
  };
  reader.readAsArrayBuffer(input.files[0]);
}
function showReorientedImage(input) {
  // [ ... read and display image using a data: URL as before ... ]
  var reader = new FileReader();
  reader.onload = function() {
    // Using https://github.com/jseidelin/exif-js/ ...
    var orientation = readEXIFTags(reader.result).Orientation;
    var rotation = [0, 0, 0, 180, 180, 90, 90, -90, -90];
    document.querySelector("img").style.transform =
      "rotate(" + (rotation[orientation] || 0) + "deg)";
  };
  reader.readAsArrayBuffer(input.files[0]);
}

Creating blob: URLs

  • data: URLs are cool, but can be slow – might be megabytes long
  • blob: URLs are like pointers to a File (or other Blob) object
  • Generates a URL with a unique ID, on the order of 100 bytes
  • Unfortunately not supported by Opera :(
var file = input.files[0];
var url = URL.createObjectURL(file);  // "blob:d719e6ca-3d89-464e-..."
img.src = url;

// If finished before the page is closed:
URL.revokeObjectURL(url);

Other neat things

  • You can pass a File to XMLHttpRequest.send()
  • You can get a File out of a DataTransfer object when handling a drop event
  • You can hide an <input type=file>, present your own UI, and invoke the open dialog with a .click()

Limitations

  • You cannot traverse a whole directory tree
    • But note that Google’s File System API doesn’t let you access arbitrary directories, either
    • IndexedDB lets you do local storage like File System API
  • You cannot save a file back with a specific filename
    • <a href="blob:..." download> might help here
  • Work progresses in standards groups to solve these problems...

Support

6+ 3.6+ 10 11+ 6

But good polyfills are available!

Thank You

Cameron McCormack, Mozilla  ·  @heycam

Shower, by Vadim Makeev, Opera Software
Mozilla styling, by Chris Heilmann, Mozilla