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');
Теперь вы вооружены знаниями для работы с файлами прямо в браузере! Пробуйте, экспериментируйте и создавайте потрясающие пользовательские интерфейсы. 🎉