JavaScript read File Reading local files with JavaScript
This is a repost from my blog For security and privacy reasons web apps do not have direct access to the files
on the user’s device. If you need to read one or multiple local files, you can do
this through the usage of a file input and a FileReader. In this post we will take a look
at how this works through a few examples.
TL;DR
- JavaScript does not have direct access to the local files due to security and privacy.
- We can offer the user the possibility to select files via a file input element that we can then process.
- The file input has a files property with the selected file(s).
- We can use a FileReader to access the content of the selected file(s).
How it works
As JavaScript in the browser cannot access the local files from the user’s device,
we need to provide the user with a way to select one or multiple files for us to use.
This can be done with the HTML file input element:
If we want to allow the selection of multiple files, we can add the multiple attribute:
type="file" id="fileInput" multiple>
We can either use the change event of the input field to respond to a file selection
or add another UI element to let the user explicitly start the processing of the selected file.
Also note: The selection of a file with the input element does not upload the file anywhere,
the only thing that happens is that the file becomes available to the JavaScript on the page.
The file input has a files property that is a list (as there could be multiple selected files) of File objects.
type="file" id="fileInput"> document.getElementById('fileInput').addEventListener('change', function selectedFileChanged() console.log(this.files); // will contain information about the file that was selected. >);
A File object looks like this:
name: 'test.txt', // the name of the selected file size: 1024, // the size in bytes type: 'text/plain', // the assumed file type based on file extension. This might be incorrect. lastModified: 1234567890, // timestamp of the last change according to the user's system lastModifiedDate: 'Thu Jul 04 2019 09:22:51 GMT+0200 (Central European Summer Time)' // a date object for the last modified timestamp >
Now we have the ability to select a file and see the metadata, but how can we access the file content?
To get the actual content of a selected file, we need a FileReader .
A file reader takes a File object and offers us methods to get access to the data as:
- a string of text data
- a data URL
- a string of binary data
- an ArrayBuffer containing raw binary data
In the following examples, we will use the readAsText and readAsDataURL methods to show the content of text and image files.
Example one: Reading text files
To show the file content as text, we change the change event handler:
document.getElementById('fileInput').addEventListener('change', function selectedFileChanged() if (this.files.length === 0) console.log('No file selected.'); return; > const reader = new FileReader(); reader.onload = function fileReadCompleted() // when the reader is done, the content is in reader.result. console.log(reader.result); >; reader.readAsText(this.files[0]); >);
First we make sure that there is a file that can be read. If the user cancels or otherwise
closes the file selection dialog without selecting a file, we have nothing to read and exit our function.
We then proceed to create a FileReader . The reader works asychronously in order
to not block the main thread and UI updates which is important when reading large files (like videos).
The reader emits a ‘load’ event (similar to images for example) that tells our code that the reading is finished.
The reader keeps the file content in its result property. The data in this property depends on which method we used to read the file.
In our example we read the file with the readAsText method, so the result will be a string of text.
Example two: Displaying an image from the user’s device
If we want to display images, reading the file into a string isn’t very helpful.
Conveniently the FileReader has a readAsDataURL method that reads the file into
an encoded string that can be used as the source for an element. The code is pretty much the same as previously,
with the exceptions that we read the file with readAsDataURL and display the result as an image:
document.getElementById('fileInput').addEventListener('change', function selectedFileChanged() if (this.files.length === 0) console.log('No file selected.'); return; > const reader = new FileReader(); reader.onload = function fileReadCompleted() const img = new Image(); // creates an
element img.src = reader.result; // loads the data URL as the image source document.body.appendChild(img); // adds the image to the body >; reader.readAsDataURL(this.files[0]); >);
File и FileReader
Объект File наследуется от объекта Blob и обладает возможностями по взаимодействию с файловой системой.
Есть два способа его получить.
Во-первых, есть конструктор, похожий на Blob :
new File(fileParts, fileName, [options])
- fileParts – массив значений Blob / BufferSource /строки.
- fileName – имя файла, строка.
- options – необязательный объект со свойством:
- lastModified – дата последнего изменения в формате таймстамп (целое число).
Во-вторых, чаще всего мы получаем файл из или через перетаскивание с помощью мыши, или из других интерфейсов браузера. В этом случае файл получает эту информацию из ОС.
Так как File наследует от Blob , у объектов File есть те же свойства плюс:
В этом примере мы получаем объект File из :
Через можно выбрать несколько файлов, поэтому input.files – псевдомассив выбранных файлов. Здесь у нас только один файл, поэтому мы просто берём input.files[0] .
FileReader
FileReader объект, цель которого читать данные из Blob (и, следовательно, из File тоже).
Данные передаются при помощи событий, так как чтение с диска может занять время.
let reader = new FileReader(); // без аргументов
- readAsArrayBuffer(blob) – считать данные как ArrayBuffer
- readAsText(blob, [encoding]) – считать данные как строку (кодировка по умолчанию: utf-8 )
- readAsDataURL(blob) – считать данные как base64-кодированный URL.
- abort() – отменить операцию.
Выбор метода для чтения зависит от того, какой формат мы предпочитаем, как мы хотим далее использовать данные.
- readAsArrayBuffer – для бинарных файлов, для низкоуровневой побайтовой работы с бинарными данными. Для высокоуровневых операций у File есть свои методы, унаследованные от Blob , например, slice , мы можем вызвать их напрямую.
- readAsText – для текстовых файлов, когда мы хотим получить строку.
- readAsDataURL – когда мы хотим использовать данные в src для img или другого тега. Есть альтернатива – можно не читать файл, а вызвать URL.createObjectURL(file) , детали в главе Blob.
В процессе чтения происходят следующие события:
- loadstart – чтение начато.
- progress – срабатывает во время чтения данных.
- load – нет ошибок, чтение окончено.
- abort – вызван abort() .
- error – произошла ошибка.
- loadend – чтение завершено (успешно или нет).
Когда чтение закончено, мы сможем получить доступ к его результату следующим образом:
Наиболее часто используемые события – это, конечно же, load и error .
Как упоминалось в главе Blob, FileReader работает для любых объектов Blob, а не только для файлов.
Поэтому мы можем использовать его для преобразования Blob в другой формат:
- readAsArrayBuffer(blob) – в ArrayBuffer ,
- readAsText(blob, [encoding]) – в строку (альтернатива TextDecoder ),
- readAsDataURL(blob) – в формат base64-кодированного URL.
Для веб-воркеров доступен синхронный вариант FileReader , именуемый FileReaderSync.
Его методы считывания read* не генерируют события, а возвращают результат, как это делают обычные функции.
Но это только внутри веб-воркера, поскольку задержки в синхронных вызовах, которые возможны при чтении из файла, в веб-воркерах менее важны. Они не влияют на страницу.
Итого
File объекты наследуют от Blob .
Помимо методов и свойств Blob , объекты File также имеют свойства name и lastModified плюс внутреннюю возможность чтения из файловой системы. Обычно мы получаем объекты File из пользовательского ввода, например, через или перетаскиванием с помощью мыши, в событии dragend .
Объекты FileReader могут читать из файла или Blob в одном из трёх форматов:
- Строка ( readAsText ).
- ArrayBuffer ( readAsArrayBuffer ).
- URL в формате base64 ( readAsDataURL ).
Однако, во многих случаях нам не нужно читать содержимое файла. Как и в случае с Blob, мы можем создать короткий URL с помощью URL.createObjectURL(file) и использовать его в теге или
. Таким образом, файл может быть загружен или показан в виде изображения, как часть canvas и т.д.
А если мы собираемся отправить File по сети, то это также легко, поскольку в сетевые методы, такие как XMLHttpRequest или fetch , встроена возможность отсылки File .
File and FileReader
A File object inherits from Blob and is extended with filesystem-related capabilities.
There are two ways to obtain it.
First, there’s a constructor, similar to Blob :
new File(fileParts, fileName, [options])
- fileParts – is an array of Blob/BufferSource/String values.
- fileName – file name string.
- options – optional object:
- lastModified – the timestamp (integer date) of last modification.
Second, more often we get a file from or drag’n’drop or other browser interfaces. In that case, the file gets this information from OS.
As File inherits from Blob , File objects have the same properties, plus:
That’s how we can get a File object from :
The input may select multiple files, so input.files is an array-like object with them. Here we have only one file, so we just take input.files[0] .
FileReader
FileReader is an object with the sole purpose of reading data from Blob (and hence File too) objects.
It delivers the data using events, as reading from disk may take time.
let reader = new FileReader(); // no arguments
- readAsArrayBuffer(blob) – read the data in binary format ArrayBuffer .
- readAsText(blob, [encoding]) – read the data as a text string with the given encoding ( utf-8 by default).
- readAsDataURL(blob) – read the binary data and encode it as base64 data url.
- abort() – cancel the operation.
The choice of read* method depends on which format we prefer, how we’re going to use the data.
- readAsArrayBuffer – for binary files, to do low-level binary operations. For high-level operations, like slicing, File inherits from Blob , so we can call them directly, without reading.
- readAsText – for text files, when we’d like to get a string.
- readAsDataURL – when we’d like to use this data in src for img or another tag. There’s an alternative to reading a file for that, as discussed in chapter Blob: URL.createObjectURL(file) .
As the reading proceeds, there are events:
- loadstart – loading started.
- progress – occurs during reading.
- load – no errors, reading complete.
- abort – abort() called.
- error – error has occurred.
- loadend – reading finished with either success or failure.
When the reading is finished, we can access the result as:
The most widely used events are for sure load and error .
Here’s an example of reading a file:
As mentioned in the chapter Blob, FileReader can read not just files, but any blobs.
We can use it to convert a blob to another format:
- readAsArrayBuffer(blob) – to ArrayBuffer ,
- readAsText(blob, [encoding]) – to string (an alternative to TextDecoder ),
- readAsDataURL(blob) – to base64 data url.
For Web Workers, there also exists a synchronous variant of FileReader , called FileReaderSync.
Its reading methods read* do not generate events, but rather return a result, as regular functions do.
That’s only inside a Web Worker though, because delays in synchronous calls, that are possible while reading from files, in Web Workers are less important. They do not affect the page.
Summary
File objects inherit from Blob .
In addition to Blob methods and properties, File objects also have name and lastModified properties, plus the internal ability to read from filesystem. We usually get File objects from user input, like or Drag’n’Drop events ( ondragend ).
FileReader objects can read from a file or a blob, in one of three formats:
- String ( readAsText ).
- ArrayBuffer ( readAsArrayBuffer ).
- Data url, base-64 encoded ( readAsDataURL ).
In many cases though, we don’t have to read the file contents. Just as we did with blobs, we can create a short url with URL.createObjectURL(file) and assign it to or
. This way the file can be downloaded or shown up as an image, as a part of canvas etc.
And if we’re going to send a File over a network, that’s also easy: network API like XMLHttpRequest or fetch natively accepts File objects.