JavaScript File Handling

Beginner
10 min read
Updated: Oct 2026
4 examples
Live preview

What Is File Handling?

Browser file handling means working with files the user chooses: inspect metadata, read text or bytes, preview images, then upload or process locally. The File API gives you File / FileList; FileReader (or file.text()) reads the contents.

Note No silent disk access

Scripts cannot open arbitrary paths. Files arrive only from a picker, drag-and-drop, or an API the user has approved.

Deprecated readAsBinaryString()

Prefer readAsArrayBuffer() or file.arrayBuffer() for binary data. Do not use readAsBinaryString in new code.

Limited support File System Access API

Permission-based open/save beyond a basic file input. Feature-detect before use; support is strongest in Chromium-based browsers.

Remember
<input type="file">  →  FileList  →  File (extends Blob)

metadata: file.name · file.size · file.type · file.lastModified

read text:   reader.readAsText(file)  or  await file.text()
preview:     URL.createObjectURL(file)  or  readAsDataURL(file)
binary:      reader.readAsArrayBuffer(file)  or  await file.arrayBuffer()
GoalPrefer
Pick a file<input type="file"> + change
Plain textawait file.text() or readAsText
Image previewURL.createObjectURL(file)
Guard uploadsCheck size / type first

How to Use File Handling

Pick → validate → read → use the result. Keep each step small and explicit.

  1. Add <input type="file"> (optional accept / multiple).
  2. On change, take event.target.files[0] (a File).
  3. Check size and type before reading large or wrong files.
  4. Read with FileReader or promise helpers (file.text()), then show, parse, or upload.
PieceRequired?Role
File input / dropYesUser grants access to a file
File / FileListYesMetadata + blob of bytes
FileReader or file.text()When readingDecode contents asynchronously
revokeObjectURLIf blob URLFree preview memory

Pseudocode

Pseudocode
on file input change:
    file = files[0]
    if no file: return

    if file.size > MAX or type not allowed:
        show error; clear input; return

    // modern
    text = await file.text()
    show(text)

    // or classic
    reader = new FileReader()
    reader.onload  → show(reader.result)
    reader.onerror → show error
    reader.readAsText(file)

Cheat Sheet

Keep these File API facts handy.

TopicDetail
Picker<input type="file">
Listinput.files → FileList
Metadataname, size, type, lastModified
TextreadAsText / file.text()
Data URLreadAsDataURL → img.src
Blob URLcreateObjectURL + revokeObjectURL
BinaryreadAsArrayBuffer / file.arrayBuffer()
Server-sideNode.js fs — not the browser File API

Live Preview

Choose a file in this browser. The demo shows name, size, and MIME type — the same first step every file handler uses.

Nothing leaves your device — this preview only reads File metadata in the page.

Result
Pick a file to inspect metadata.

file.name → …
file.size → …
file.type → …

JavaScript Examples

Short, copy-ready snippets. Pair each with a file input on the page, or open Try It Yourself for a live editor.

Example 1 — Inspect File Metadata

Log name, size, and MIME type as soon as the user picks a file — no reader needed.

JavaScript
const fileInput = document.getElementById("fileInput");

fileInput.addEventListener("change", (event) => {
  const file = event.target.files[0];
  if (!file) return;

  console.log("Name:", file.name);
  console.log("Size (KB):", (file.size / 1024).toFixed(1));
  console.log("Type:", file.type || "(empty)");
});
Try It Yourself

How It Works

  1. Listen for change. The picker fires when the user confirms a selection.
  2. Take the first file. files[0] is a File from the FileList.
  3. Read metadata only. name, size, and type are available immediately.
  4. Empty MIME. Some OS files report type === "" — fall back to the extension when needed.

Example 2 — Read Text with FileReader

Decode a plain-text file and put the string into a <pre> element.

JavaScript
const fileInput = document.getElementById("fileInput");
const output = document.getElementById("fileContent");

fileInput.addEventListener("change", (event) => {
  const file = event.target.files[0];
  if (!file) return;

  const reader = new FileReader();

  reader.onload = () => {
    output.textContent = reader.result;
  };

  reader.onerror = () => {
    output.textContent = "Could not read file.";
  };

  reader.readAsText(file);
});
Try It Yourself

How It Works

  1. Create a reader. new FileReader() is async and event-based.
  2. Hook success. On load, reader.result holds the UTF-8 string.
  3. Hook failure. onerror avoids silent failures.
  4. Start the read. readAsText(file) moves state EMPTY → LOADING → DONE.

Example 3 — Preview an Image with a Blob URL

Create a temporary object URL and assign it to an <img> — prefer this over data URLs for large photos.

JavaScript
const fileInput = document.getElementById("fileInput");
const preview = document.getElementById("preview");
let objectUrl = "";

fileInput.addEventListener("change", (event) => {
  const file = event.target.files[0];
  if (!file || !file.type.startsWith("image/")) return;

  if (objectUrl) URL.revokeObjectURL(objectUrl);
  objectUrl = URL.createObjectURL(file);
  preview.src = objectUrl;
  preview.alt = "Preview of " + file.name;
});
Try It Yourself

How It Works

  1. Guard the type. Skip non-images with file.type.startsWith("image/").
  2. Revoke the old URL. Avoid leaking blob URLs when the user picks again.
  3. Create a new URL. createObjectURL(file) points at the file bytes in memory.
  4. Set img.src. The browser paints the preview without a full base64 string.

Example 4 — Validate, Then Use file.text()

Reject oversized or wrong types, then read with the modern promise helper.

JavaScript
const MAX_BYTES = 1024 * 1024; // 1 MB
const fileInput = document.getElementById("fileInput");
const output = document.getElementById("fileContent");

fileInput.addEventListener("change", async (event) => {
  const file = event.target.files[0];
  if (!file) return;

  if (file.size > MAX_BYTES) {
    output.textContent = "File is too large. Max size is 1 MB.";
    fileInput.value = "";
    return;
  }
  if (!file.type.startsWith("text/") && !file.name.endsWith(".txt")) {
    output.textContent = "Only plain text files are allowed.";
    fileInput.value = "";
    return;
  }

  try {
    output.textContent = await file.text();
  } catch (err) {
    output.textContent = "Could not read file.";
  }
});
Try It Yourself

How It Works

  1. Cap size early. Avoid loading huge files into memory.
  2. Check type + extension. MIME can be empty; extension is a useful fallback.
  3. Reset the input. fileInput.value = "" lets the user re-pick the same file.
  4. Await text. file.text() returns a promise — wrap in try/catch for errors.

Edge Cases & Pitfalls

Check these before shipping file pickers.

security

accept is only a hint

Users can bypass the filter. Always validate size / type in JS and again on the server.

mime

Empty file.type

Some platforms leave MIME blank. Combine with extension checks when classifying files.

memory

Forgotten blob URLs

Call URL.revokeObjectURL when replacing previews so memory does not grow with every pick.

api

Browser ≠ Node fs

The File API runs in the page. Reading server disks uses Node fs (or fetch) — never expose raw server paths to clients.

Browser & Runtime Support

Browser File / FileReader and <input type="file"> are Baseline DOM APIs. In Node.js, read and write disk files with the fs / fs.promises module — not FileReader or a file input.

✓ Baseline · File API

File API & FileReader

Full support in Chrome, Firefox, Safari, Edge, and modern mobile browsers. Node.js / Bun / Deno: use fs (or equivalent) for server disk I/O. Global File/Blob exist in modern Node (20+), but picker + FileReader workflows stay browser-only.

98% Browser File API
Google Chrome Supported · Desktop & Mobile
Full support
Mozilla Firefox Supported · Desktop & Mobile
Full support
Apple Safari Supported · macOS & iOS
Full support
Microsoft Edge Supported · Chromium
Full support
Opera Supported · Modern versions
Full support
Samsung Internet Supported · Android
Full support
Android WebView Supported · Modern WebView
Full support
Internet Explorer IE 10+ partial FileReader · Legacy only
Partial / obsolete
Node.js Use fs / fs.promises · not FileReader
Different API
Bun Use Bun.file / fs · not FileReader
Different API
Deno Use Deno.readFile · not FileReader
Different API
Browsers Excellent

Bottom line: For web apps, the File API is production-safe. For Node.js servers, use fs.readFile / fs.promises.readFile (and related APIs) — do not expect browser FileReader or <input type="file"> in Node.

Performance Notes

ApproachCostBest for
Metadata onlyO(1)Guards before reading
createObjectURLCheap handleLarge image previews
readAsDataURLBase64 expandSmall images / need a data URL
Full readAsTextO(n) memoryModest text / CSV / JSON

Reading loads the whole file into memory. Cap size on the client, prefer blob URLs for big media, and process huge uploads on the server (streaming / chunking) when possible.

Key Takeaways

  • Access: only user-selected files via picker or drop.
  • Read: FileReader or await file.text() / arrayBuffer().
  • Preview: prefer createObjectURL + revokeObjectURL.
  • Safety: validate in the browser for UX; re-validate on the server.

One line: pick a File, validate size/type, read with FileReader or file.text(), and revoke blob URLs when done.

Frequently Asked Questions

No. In the browser, scripts only get files the user picks through <input type="file">, drag-and-drop, or a permission-based picker such as the File System Access API. Arbitrary disk paths are not allowed.
A File object is the selected file (name, size, type, lastModified) and extends Blob. FileReader reads that File asynchronously and delivers the result through load, error, and abort events.
Both return UTF-8 text. Prefer await file.text() for short async handlers. Use FileReader when you need progress events, abort(), or older environments without Blob promise helpers.
Use URL.createObjectURL(file) for large image previews (faster, less memory). Use readAsDataURL when you need a data: URL string. Always call URL.revokeObjectURL when a blob URL is no longer needed.
Not to arbitrary paths. You can trigger a download with a Blob and an <a download> link, or use the File System Access API where supported after the user grants save permission. Server-side Node.js uses fs.
No. accept and file.type improve UX but are not a security boundary. Always re-validate size, type, and content on the server before trusting an upload.

Next: Array

Process lists of values after you parse text, CSV, or JSON from a file.

Array tutorial →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

9 people found this page helpful