Чтение файлов средствами JavaScript
Как выбирать файлы, читать метаданные и содержимое файлов, а также отслеживать прогресс чтения.
Возможность выбирать файлы на локальном устройстве пользователя и взаимодействовать с ними — это одна из наиболее часто используемых функций Интернета. С помощью этой функции пользователи могут выбирать файлы и загружать их на сервер, например, загружать фотографии или подавать налоговую отчетность и т. д. Кроме того, функция также позволяет сайтам читать файлы и управлять ими без необходимости передачи данных по сети.
Современный API доступа к файловой системе #
API доступа к файловой системе обеспечивает простой способ чтения и записи файлов и каталогов в локальной системе пользователя. В настоящее время он доступен в большинстве браузеров на основе Chromium, таких как Chrome или Edge. Чтобы узнать больше об этом, прочитайте статью «API доступа к файловой системе».
Поскольку API доступа к файловой системе еще не совместим со всеми браузерами, обратите внимание на вспомогательную библиотеку browser-fs-access, которая использует новый API везде, где это возможно, но возвращается к устаревшим подходам, если API недоступен.
Классический способ работы с файлами #
В этом руководстве показано, как:
- выбрать файлы
- прочитать метаданные файла;
- прочитать содержимое файла.
Выбор файлов #
Элемент ввода HTML #
Самый простой способ разрешить пользователям выбирать файлы — это использовать элемент <input type="file">
, который поддерживается во всех основных браузерах. После щелчка он позволяет пользователю выбрать один файл или несколько файлов, если включен атрибут multiple
, используя встроенный в операционную систему пользовательский интерфейс выбора файлов. Когда пользователь завершает выбор файла или файлов, срабатывает событие элемента change
. Вы можете получить доступ к списку файлов из event.target.files
, который представляет собой объект FileList
. Каждый элемент в FileList
является объектом File
.
<!-- The `multiple` attribute lets users select multiple files. -->
<input type="file" id="file-selector" multiple>
<script>
const fileSelector = document.getElementById('file-selector');
fileSelector.addEventListener('change', (event) => {
const fileList = event.target.files;
console.log(fileList);
});
</script>
В этом примере пользователь может с помощью встроенного в операционную систему пользовательского интерфейса выбора файлов выбрать несколько файлов, которые затем записываются в консоль.
Ограничьте типы файлов, которые пользователь может выбрать #
В некоторых случаях вы можете захотеть ограничить типы файлов, которые могут выбирать пользователи. Например, приложение для редактирования изображений должно принимать только изображения, а не текстовые файлы. Для этого вы можете добавить accept
к элементу ввода, чтобы указать, какие файлы принимаются.
<input type="file" id="file-selector" accept=".jpg, .jpeg, .png">
Пользовательское перетаскивание #
В некоторых браузерах элемент <input type="file">
также является объектом-приёмником, что позволяет пользователям перетаскивать файлы в приложение. Но объект-приёмник мал, поэтому это неудобно. Вместо этого, после предоставления базовой функциональности с помощью <input type="file">
, предоставьте большую настраиваемую область перетаскивания.
Выберите область перетаскивания #
Область объекта-приёмника зависит от дизайна вашего приложения. Вы можете захотеть, чтобы только часть окна была областью перетаскивания, или, возможно, всё окно.

Squoosh позволяет пользователю перетаскивать изображение в любом месте окна, а щелчок по значку выбора изображения вызывает элемент <input type="file">
. Что бы вы ни выбрали в качестве объекта-приёмника, убедитесь, что пользователю понятно, что он может перетаскивать файлы в эту область.
Определите область перетаскивания #
Чтобы включить элемент в зону перетаскивания, необходимо прослушать два события, dragover
и drop
. Событие dragover
обновляет пользовательский интерфейс браузера, чтобы визуально показать, что действие перетаскивания создает копию файла. Событие drop
запускается после того, как пользователь опускает файлы на область перетаскивания. Аналогично элементу ввода, вы можете получить доступ к списку файлов из event.dataTransfer.files
, который представляет собой объект FileList
. Каждый элемент в FileList
является объектом File
.
const dropArea = document.getElementById('drop-area');
dropArea.addEventListener('dragover', (event) => {
event.stopPropagation();
event.preventDefault();
// Style the drag-and-drop as a "copy file" operation.
event.dataTransfer.dropEffect = 'copy';
});
dropArea.addEventListener('drop', (event) => {
event.stopPropagation();
event.preventDefault();
const fileList = event.dataTransfer.files;
console.log(fileList);
});
События event.stopPropagation()
и event.preventDefault()
останавливают поведение браузера по умолчанию и позволяют вместо этого запускаться вашему коду. Без них браузер ушел бы с вашей страницы и открывал файлы, которые пользователь поместил в окно браузера.
Посмотрите живую демонстрацию настраиваемой области перетаскивания.
А как насчет каталогов? #
К сожалению, на сегодня нет хорошего способа получить доступ к каталогу.
Атрибут webkitdirectory
элемента <input type="file">
позволяет пользователю выбрать каталог или каталоги. Он поддерживается некоторыми браузерами на основе Chromium и, возможно, настольной версией Safari, но имеются противоречивые сведения о совместимости с другими браузерами.
Если перетаскивание включено, пользователь может попытаться перетащить каталог в область перетаскивания. Когда запускается событие drop, оно будет включать File
для каталога, но не сможет получить доступ ни к одному из файлов в каталоге.
Чтение метаданных файла #
Объект File
содержит ряд свойств метаданных о файле. Большинство браузеров предоставляют имя файла, размер файла и тип MIME, хотя в зависимости от платформы разные браузеры могут предоставлять различную или дополнительную информацию.
function getMetadataForFileList(fileList) {
for (const file of fileList) {
// Not supported in Safari for iOS.
const name = file.name ? file.name : 'NOT SUPPORTED';
// Not supported in Firefox for Android or Opera for Android.
const type = file.type ? file.type : 'NOT SUPPORTED';
// Unknown cross-browser support.
const size = file.size ? file.size : 'NOT SUPPORTED';
console.log({file, name, type, size});
}
}
Вы можете увидеть это в действии в демонстрации Glitch input-type-file
.
Чтение содержимого файла #
Чтобы прочитать файл, используйте объект FileReader
, который позволяет читать содержимое File
в память. Вы можете указать для объекта FileReader
методы чтения файлов ArrayBuffer, dataURL или text.
function readImage(file) {
// Check if the file is an image.
if (file.type && !file.type.startsWith('image/')) {
console.log('File is not an image.', file.type, file);
return;
}
const reader = new FileReader();
reader.addEventListener('load', (event) => {
img.src = event.target.result;
});
reader.readAsDataURL(file);
}
В приведенном выше примере считывается предоставленный пользователем File
, затем он преобразуется в Data URL, который используется для отображения изображения в элементе img
. Ознакомьтесь с примером на Glitch read-image-file
, чтобы узнать, как проверить, выбрал ли пользователь файл изображения.
Отслеживайте процесс чтения файла #
При чтении больших файлов будет целесообразно предоставлять определенный интерфейс UX, показывающий насколько далеко продвинулось чтение. Для этого используйте событие progress
, предоставляемое FileReader
. Событие progress
предоставляет два свойства: количество почитанного loaded
и общий объем чтения total
.
function readFile(file) {
const reader = new FileReader();
reader.addEventListener('load', (event) => {
const result = event.target.result;
// Do something with result
});
reader.addEventListener('progress', (event) => {
if (event.loaded && event.total) {
const percent = (event.loaded / event.total) * 100;
console.log(`Progress: ${Math.round(percent)}`);
}
});
reader.readAsDataURL(file);
}
Главное изображение взято у Vincent Botta на Unsplash