Файлы в JavaScript: как читать, записывать и обрабатывать данные

Раздел: 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.

js файлы - comments

En
Js file (javascript)