How to upload files on the Web

#ProgrammingThu Oct 24 2024

How to upload and preview files on the web? I had a task where I needed to upload an image and display a thumbnail on the screen the other day. While working on file uploads on the web, I started to wonder what exactly a blob format is, why we use FileReader, and what binary data means.

Blob as the File Format

An input tag for uploading files looks like this:

<input type="file" />

Here, the format of the file is blob. A Blob object represents a file-like data object that can be read as text or binary data. You can convert it into a ReadableStream and process the data using its methods.

Blob Methods

  • Blob.arrayBuffer(): Returns a promise that resolves with the blob’s entire content as a binary ArrayBuffer.
  • Blob.slice(): Creates and returns a new Blob object containing a portion of the original blob's data, starting and ending at the specified byte range.
  • Blob.stream(): Returns a ReadableStream to read the contents of the Blob.
  • Blob.text(): Returns a promise that resolves with the blob’s entire content as a UTF-8 text string.

Reference: Blob - Web API | MDN

Binary Data and Base64

The file format is blob, and blob can be read as binary data. Binary data consists of ones and zeros, and all data and files are essentially binary. When saving images, they are stored as bytes (binary). If you want to display this saved binary data image on the screen, you need to convert it to base64 format. You can use the btoa method in JavaScript for this. The btoa method creates a base64-encoded ASCII string from binary data, and atob() can be used to decode the data back.

Reference: WindowOrWorkerGlobalScope.btoa() - Web APIs | MDN

FileReader

The FileReader API allows you to read the content of blobs or files. A FileReader object provides methods to read the content of files or blobs, making it possible to save them to your computer. You can obtain a File object from an input tag where users select files or from a DataTransfer object after a drag-and-drop operation.

const reader = new FileReader();
reader.addEventListener('loadend', () => {
   // reader.result contains the contents of the blob as a typed array
});
reader.readAsArrayBuffer(blob);

FileReader Event Handlers

  • FileReader.onabort: Triggered when the reading operation is aborted.
  • FileReader.onerror: Triggered when an error occurs during the reading process.
  • FileReader.onload: Triggered when the reading operation is successfully completed.
  • FileReader.onloadstart: Triggered when the reading process starts.
  • FileReader.onloadend: Triggered when the reading process is finished.
  • FileReader.onprogress: Triggered while reading the blob content.

Note: Since FileReader inherits from EventTarget, all events mentioned above can be listened to using addEventListener.

Displaying the User's Selected Image

The MDN document Using files from web applications provides an example using vanilla JavaScript. Since I’m working on a project with React Hooks, I wrote my own version of the code. I'm sure there’s a better way out there somewhere, but here’s my attempt!

import React, { useState } from 'react';

export default () => {
  const [file, setFile] = useState(null);
  const [url, setUrl] = useState("");

  const handleChange = (e) => {
    const selectedFile = e.target.files[0];
    setFile(selectedFile);

    const reader = new FileReader();
    reader.onload = () => {
      setUrl(reader.result);
    };
    reader.readAsDataURL(selectedFile);
  };

  return (
    <div>
      <input type="file" onChange={handleChange} />
      <img file={file} src={url} />
    </div>
  );
};

In this example, I stored the selected file in a state variable and added a file attribute to the image. Adding this attribute makes it possible to later fetch the image for uploading. I created a new FileReader object and set up the onload function. As we discussed earlier, the onload event triggers when the reading operation is successfully completed. Once the file is successfully read, I set the URL. You can set this URL as the src attribute of the image tag, which will display the image on the screen.

When the image file’s entire content is loaded, the img element's src attribute is set to the loaded image, displaying the image on the page.