Файлы в JavaScript: как читать, записывать и обрабатывать данные
Основные подходы к работе с файлами в JavaScript
Наиболее универсальный способ чтения содержимого файла на стороне клиента - использование объекта FileReader. Он позволяет асинхронно прочитать данные из файла, выбранного пользователем через элемент <input type="file">, и преобразовать их в строку, бинарный буфер или Data URL. Пример базового чтения текстового файла:
const input = document.querySelector('#fileInput');
input.addEventListener('change', (event) => {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
console.log('Содержимое файла:', e.target.result);
};
reader.readAsText(file);
});Js file (js файлы)
Результат: в консоль выводится текст выбранного файла. Важно: метод readAsText подходит только для текстовых файлов (txt, csv, html). Для изображений используют readAsDataURL, для бинарных данных - readAsArrayBuffer.
Типичная ошибка: попытка прочитать файл до того, как пользователь его выбрал (file === null). Рекомендуется проверять наличие файла. Другая проблема - некорректная кодировка (например, файл в UTF-16, а чтение идёт в UTF-8). Решение: при вызове readAsText(file, 'windows-1251') можно указать кодировку вторым аргументом.
Как загрузить файл на сервер с помощью fetch?
Для отправки файла на сервер чаще всего используют объект FormData вместе с fetch. Файл из input[type=file] добавляется в FormData, и отправляется POST-запрос:
const formData = new FormData();
formData.append('file', file);
fetch('/upload', {
method: 'POST',
body: formData
}).then(response => response.json()).then(data => console.log(data));Сервер должен обрабатывать multipart/form-data. Проблемы: превышение лимита размера файла, отсутствие CORS-заголовков при кросс-доменной отправке. Решение: на сервере настроить maxFileSize и разрешить CORS.
Как прочитать несколько файлов одновременно?
Если у input стоит атрибут multiple, то event.target.files - это псевдомассив FileList. Можно перебрать все файлы и прочитать каждый:
Array.from(event.target.files).forEach(file => {
const reader = new FileReader();
reader.onload = (e) => {
// обработать e.target.result
};
reader.readAsDataURL(file);
});Проблема: большое количество файлов может вызвать перегрузку памяти. Решение: чтение последовательно, с использованием очереди или библиотек (например, file-saver).
Как сохранить данные в файл на клиенте?
Для сохранения данных (например, сгенерированного на странице текста) используют комбинацию Blob и URL.createObjectURL:
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'data.json';
link.click();
URL.revokeObjectURL(url);Проблема: в старых браузерах отсутствует URL.revokeObjectURL, возможна утечка памяти. Решение: использовать полифил или библиотеку FileSaver.js.
Как работать с файловой системой в Node.js?
В среде Node.js для работы с файлами используется встроенный модуль fs. Чтение текстового файла синхронно: const text = fs.readFileSync('./file.txt', 'utf-8');. Асинхронно: fs.readFile('./file.txt', 'utf-8', (err, data) => {...}). Запись: fs.writeFileSync('./out.txt', content). Проблемы: ошибка ENOENT при отсутствии файла, переполнение буфера для больших файлов. Решение: перед чтением проверять существование файла с помощью fs.existsSync (устарел, лучше fs.access), для больших файлов использовать потоки (streams).
Расширенные примеры работы с файлами
Ниже представлены более сложные сценарии, демонстрирующие обработку файлов различных типов и интеграцию с другими API.
Чтение CSV и преобразование в массив объектов
function parseCSV(csvText) {
const lines = csvText.split('\n').filter(line => line.trim());
if (lines.length === 0) return [];
const headers = lines[0].split(',');
return lines.slice(1).map(line => {
const values = line.split(',');
return headers.reduce((obj, header, index) => {
obj[header.trim()] = values[index]?.trim();
return obj;
}, {});
});
}
// Использование с FileReader
const fileInput = document.getElementById('csvInput');
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (evt) => {
const data = parseCSV(evt.target.result);
console.log(data);
};
reader.readAsText(file);
});[ { "name": "Иван", "age": "30" }, { "name": "Мария", "age": "25" } ]Загрузка изображения и отображение превью
document.getElementById('imageInput').addEventListener('change', (e) => {
const file = e.target.files[0];
if (file && file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = (evt) => {
const img = document.createElement('img');
img.src = evt.target.result;
document.getElementById('preview').appendChild(img);
};
reader.readAsDataURL(file);
} else {
alert('Выберите изображение');
}
});На странице появляется элемент <img> с загруженным изображением.
Асинхронное чтение с помощью Promise и async/await
function readFileAsText(file, encoding = 'utf-8') {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(reader.error);
reader.readAsText(file, encoding);
});
}
// Использование
async function handleFiles(files) {
for (const file of files) {
try {
const text = await readFileAsText(file);
console.log('Прочитан файл:', file.name, text.substring(0, 100));
} catch (err) {
console.error('Ошибка чтения', file.name, err);
}
}
}
document.getElementById('multiFile').addEventListener('change', (e) => handleFiles(e.target.files));Последовательное асинхронное чтение всех выбранных файлов.
Работа с потоками в Node.js (streams) для больших файлов
const fs = require('fs');
const readStream = fs.createReadStream('./large.txt', { encoding: 'utf-8', highWaterMark: 1024 });
readStream.on('data', (chunk) => {
console.log('Получен фрагмент:', chunk.length, 'символов');
// обработка chunk
});
readStream.on('end', () => console.log('Файл прочитан полностью'));
readStream.on('error', (err) => console.error('Ошибка:', err));Вывод в консоль нескольких фрагментов текста из файла.
Сохранение сгенерированного двоичного файла (например, zip-архива)
// Предположим, что есть функция, генерирующая Uint8Array с ZIP-данными
const zipData = generateZip();
const blob = new Blob([zipData], { type: 'application/zip' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'archive.zip';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);Браузер скачивает файл archive.zip.