File and FileReader

A File is a specialized kind of Blob. It carries all the binary machinery a Blob has, then adds the two things a real filesystem entry needs: a name and a “last modified” timestamp. Because File sits on top of Blob, everything you already know about blobs — size, type, slice() — works on a File unchanged.

Blob
size
type
slice()
+
File adds
name
lastModified
read from disk
File is a Blob plus filesystem metadata

Two ways to get a File

One: the constructor. It mirrors the Blob constructor but takes a name in the middle:

new File(fileParts, fileName, [options])
  • fileParts — an array of Blob, BufferSource, or String values, the same shape you’d pass to new Blob([...]).
  • fileName — the file name, as a string.
  • options — optional object:
    • lastModified — the timestamp (an integer date) of the last modification.

You’d build a File by hand when you generate content in the browser — say, exporting a canvas or bundling text — and want to hand it to code that expects a real file, like a fetch upload.

Two: the browser hands you one. This is the common case. When a user picks a file through <input type="file">, drops one onto the page, or pastes an image, the browser creates the File for you and fills in name and lastModified from the operating system. You don’t set those values; they describe the actual file on the user’s disk.

Since File inherits from Blob, a File object has every Blob property, plus:

  • name — the file name.
  • lastModified — the timestamp of the last modification.

Here’s how you read a File out of an <input type="file">:

<input type="file" onchange="inspectFile(this)">

<script>
function inspectFile(input) {
  let file = input.files[0];

  alert(`File name: ${file.name}`); // e.g. quarterly-report.pdf
  alert(`Last modified: ${file.lastModified}`); // e.g. 1699887654321
}
</script>

FileReader

FileReader exists to do one job: pull data out of a Blob (and therefore out of a File, which is a Blob). It doesn’t create files or write them — it reads.

Reading from disk can take real time, so FileReader doesn’t block and return a value. It works asynchronously and reports back through events. You kick off a read, then wait for the browser to tell you it’s done.

The constructor takes nothing:

let reader = new FileReader(); // no arguments

The read methods

Each method starts a read and produces the result in a particular format:

  • readAsArrayBuffer(blob) — read the raw bytes into an ArrayBuffer.
  • readAsText(blob, [encoding]) — decode the bytes into a string using the given encoding (utf-8 by default).
  • readAsDataURL(blob) — read the bytes and encode them as a base64 data: URL.
  • abort() — stop a read that’s in progress.

Which one you pick comes down to how you plan to use the data:

  • readAsArrayBuffer — for binary files where you need byte-level access. If you only want high-level operations like slicing, you don’t need to read at all: File inherits slice() from Blob, so you can call it directly.
  • readAsText — for text files, when you want a plain string back.
  • readAsDataURL — when the data goes straight into a src, like an <img> or <a>. There’s a lighter alternative for that specific case — URL.createObjectURL(file), covered in the Blob chapter — which hands you a URL without decoding the whole file into base64.

The events

As a read proceeds, FileReader fires events in order:

  • loadstart — reading has started.
  • progress — fired periodically while reading.
  • load — reading completed with no error.
  • abortabort() was called.
  • error — an error occurred.
  • loadend — reading finished, whether it succeeded or failed.
loadstart
progress…
load ✓
or
error ✗
loadend
FileReader event flow after you call a read method

Once a read finishes, two properties hold the outcome:

  • reader.result — the result, on success.
  • reader.error — the error, on failure.

In practice you’ll wire up load and error far more than the rest.

Here’s a full read of a text file:

<input type="file" onchange="readFile(this)">

<script>
function readFile(input) {
  let file = input.files[0];

  let reader = new FileReader();

  reader.readAsText(file);

  reader.onload = function() {
    console.log(reader.result);
  };

  reader.onerror = function() {
    console.log(reader.error);
  };

}
</script>

Summary

File objects inherit from Blob.

On top of the Blob methods and properties, a File adds name and lastModified, plus the built-in ability to read from the filesystem. You most often get File objects from user input — an <input> or drag-and-drop events (ondragend).

FileReader reads a file or a blob into one of three formats:

  • String — readAsText.
  • ArrayBufferreadAsArrayBuffer.
  • Base64 data URL — readAsDataURL.

Often you don’t need to read the contents at all. As with blobs, you can mint a short URL with URL.createObjectURL(file) and assign it to an <a> or <img> — the file downloads, shows as an image, feeds a canvas, and so on.

And sending a File over the network is straightforward: APIs like XMLHttpRequest and fetch accept File objects natively.