FileReader: чтение файлов на стороне клиента

Введение: магия чтения файлов прямо в браузере ✨

Представьте: пользователь загружает изображение, и вы мгновенно показываете его превью — без отправки на сервер! Это возможно благодаря объекту FileReader. Давайте разберёмся, как это работает и как сделать процесс гладким и удобным.


Как получить файл от пользователя 🏗️

Всё начинается с элемента <input type="file">. Вот базовый пример:

<input type="file" id="fileInput">
<button id="uploadButton">Загрузить</button>
<div id="preview"></div>
document.getElementById('uploadButton').addEventListener('click', () => {
  const fileInput = document.getElementById('fileInput');
  if (fileInput.files.length > 0) {
    const file = fileInput.files[0];
    console.log('Выбран файл:', file.name, file.size + 'bytes', file.type);
  }
});

💡 fileInput.files — это FileList, коллекция выбранных файлов. Даже если multiple-атрибут не указан, это всё равно массив!


Создаём FileReader и читаем файлы 📖

Основные методы FileReader:

  • readAsText() — для текстовых файлов
  • readAsDataURL() — для изображений/бинарных данных (base64)
  • readAsArrayBuffer() — для сложной бинарной обработки

Пример чтения изображения:

function previewImage(file) {
  const reader = new FileReader();

  reader.onload = function(e) {
    const preview = document.getElementById('preview');
    preview.innerHTML = `<img src="${e.target.result}" style="max-width: 300px;">`;
  };

  reader.onerror = function() {
    console.error('Ошибка чтения файла!');
  };

  reader.readAsDataURL(file);
}

🔥 Важно! Обработчики (onload, onerror) должны быть назначены до вызова методов чтения.


Отслеживаем прогресс загрузки 📊

Для больших файлов полезно показывать прогресс:

reader.onprogress = function(e) {
  if (e.lengthComputable) {
    const percentLoaded = Math.round((e.loaded / e.total) * 100);
    console.log(`Загружено: ${percentLoaded}%`);
    // Можно обновлять прогресс-бар
  }
};

Реальные кейсы использования 🛠️

1. Валидация перед загрузкой

Проверяем тип и размер файла:

const MAX_SIZE = 5 * 1024 * 1024; // 5MB

if (!file.type.match('image.*')) {
  alert('Только изображения!');
  return;
}

if (file.size > MAX_SIZE) {
  alert('Файл слишком большой!');
  return;
}

2. Чтение CSV-файла

reader.readAsText(file);
reader.onload = function(e) {
  const lines = e.target.result.split('\n');
  const data = lines.map(line => line.split(','));
  console.log('CSV данные:', data);
};

3. Предпросмотр нескольких изображений

function handleMultipleFiles(files) {
  Array.from(files).forEach(file => {
    const reader = new FileReader();
    reader.onload = (e) => {
      // Добавляем каждое изображение в галерею
    };
    reader.readAsDataURL(file);
  });
}

Лучшие практики и подводные камни ⚠️

1. Всегда обрабатывайте ошибки:

reader.onerror = () => {
   console.error('Код ошибки:', reader.error.code);
};

2. Освобождайте ресурсы: После использования прервите чтение, если оно больше не нужно:

reader.abort();

3. Оптимизируйте память: Для больших файлов используйте URL.createObjectURL() вместо FileReader:

const imgUrl = URL.createObjectURL(file);
imgElement.src = imgUrl;
// Не забудьте потом вызвать URL.revokeObjectURL(imgUrl)

Современная альтернатива: File API 🆕

Современные браузеры поддерживают более простые способы:

// Чтение текста (Async/Await)
const text = await file.text();

// Чтение как DataURL
const dataUrl = await file.dataUrl();

Но FileReader всё равно нужен для:

  • Отслеживания прогресса
  • Чтения ArrayBuffer
  • Поддержки старых браузеров

Закрепляем на практике 🏋️

Давайте создадим компонент для загрузки аватара с превью и валидацией:

class AvatarUploader {
  constructor(inputId, previewId, maxSize = 2 * 1024 * 1024) {
    this.input = document.getElementById(inputId);
    this.preview = document.getElementById(previewId);
    this.maxSize = maxSize;

    this.input.addEventListener('change', this.handleFileSelect.bind(this));
  }

  handleFileSelect(event) {
    const file = event.target.files[0];

    if (!file.type.startsWith('image/')) {
      alert('Пожалуйста, выберите изображение!');
      return;
    }

    if (file.size > this.maxSize) {
      alert(`Файл слишком большой! Максимум ${this.maxSize / 1024 / 1024}MB`);
      return;
    }

    const reader = new FileReader();
    reader.onload = (e) => {
      this.preview.innerHTML = `
        <img src="${e.target.result}" class="avatar-preview">
        <div>${file.name} (${Math.round(file.size / 1024)}KB)</div>
      `;
    };
    reader.readAsDataURL(file);
  }
}

// Использование
new AvatarUploader('avatarInput', 'avatarPreview');

Теперь вы вооружены знаниями для работы с файлами прямо в браузере! Пробуйте, экспериментируйте и создавайте потрясающие пользовательские интерфейсы. 🎉

Скрыть рекламу навсегда

🎥 YouTube: программирование простым языком

Канал, где я спокойно и по шагам объясняю сложные темы — без заумных терминов и лишней теории.

Подходит, если раньше «не заходило», но хочется наконец понять.

▶️ Смотреть курсы на YouTube