Як прочитати текстовий файл у JS




Як прочитати текстовий файл у JS



Робота з файлами в JavaScript

Думка про те, що JavaScript не вміє взаємодіяти з файловою системою, не зовсім вірна. Скоріше йдеться про те, що ця взаємодія істотно обмежена в порівнянні з серверними мовами програмування, такими як Node.js або PHP. Тим не менш, JavaScript вміє як отримувати (приймати), так і створювати деякі типи файлів та успішно обробляти їх нативними засобами.

У цій статті ми створимо три невеликі проекти:

  • Реалізуємо отримання та обробку зображень, аудіо, відео та тексту у форматі txt та pdf
  • Створимо генератор JSON-файлів
  • Напишемо дві програми: одна формуватиме питання (у форматі JSON), а інша використовуватиме їх для створення тесту

Отримуємо та обробляємо файли

Для початку створимо директорію, в якій зберігатимуться наші проекти. Назвемо її "Work-With-Files-in-JavaScript" або як Вам завгодно.

У цій директорії створимо папку для першого проекту. Назвемо її "File-Reader".

Створюємо в ній файл "index.html" наступного змісту:

Тут ми маємо контейнер-файлоприймач та інпут із типом «file» (для отримання файлу; ми будемо працювати з одиночними файлами; для отримання декількох файлів інпуту слід додати атрибут «multiple»), який буде захований під контейнером.

Стилі можна підключити окремим файлом або в тезі style всередині head:

body < margin: 0 auto; display: flex; justify-content: center; align-items: center; min-height: 100vh; max-width: 768px; background: radial-gradient( circle, skyblue, steelblue); color: #222; >div < width: 150px; height: 150px; display: flex; justify-content: center; align-items: center; font-size: 10em; font-weight: bold; border: 6px solid; border-radius: 8px; user-select: none; cursor: pointer; >input < display: none; >img, audio, video

Можете зробити дизайн на свій смак.

Не забуваємо підключити скрипт або в head з атрибутом "defer" (нам потрібно дочекатися малювання (рендерингу) DOM; можна, звичайно, зробити це в скрипті через обробку події "load" або "DOMContentLoaded" об'єкта "window", але defer набагато коротше) , або перед тегом, що закриває, «body» (тоді не потрібен ні атрибут, ні обробник). Особисто я віддаю перевагу першому варіанту.

Відкриємо index.html у браузері:

Перш ніж переходити до написання скрипта, слід підготувати файли для програми: нам знадобиться зображення, аудіо, відео, текст у форматі txt, pdf та будь-якому іншому, наприклад, doc. Можете використати мою колекцію чи зібрати свою.

Нам часто доведеться звертатися до об'єктів «document» та «document.body», а також кілька разів виводити результати в консоль, тому пропоную обернути наш код у таке IIFE (це не обов'язково):

;((D, B, log = arg => console.log(arg)) => < // наш код // це дозволить звертатися до document і document.body як до D і B, відповідно // log = arg = >console.log(arg) - тут ми використовуємо параметри за замовчуванням // це дозволить викликати console.log як log >)(document, document.body)


Насамперед оголошуємо змінні для файлоприймача, інпуту та файлу (останній не ініціалізуємо, оскільки його значення залежить від способу передачі через клік по інпуту або кидання (drop) у файлоприймач):

const dropZone = D.querySelector('div') const input = D.querySelector('input') let file

Відключаємо обробку подій «dragover» та «drop» браузером:

D.addEventListener('dragover', ev => ev.preventDefault()) D.addEventListener('drop', ev => ev.preventDefault())

Щоб зрозуміти, навіщо ми це зробили, спробуйте перенести зображення або інший файл у браузер і подивіться, що станеться. А відбувається автоматичне оброблення файлів, тобто. те, що ми збираємося реалізувати самостійно з пізнавальною метою.

Обробляємо кидання файлу у файлоприймач:

dropZone.addEventListener('drop', ev => < // відключаємо поведінку за умовчанням ev.preventDefault() // дивимося на те, що отримуємо log(ev.dataTransfer) // отримуємо наступне (у разі передачі зображення) /* DataTransfer dropEffect: "none" effectAllowed: "all" => files: FileList length: 0 __proto__: FileList items: DataTransferItemList types: [] __proto__: DataTransfer */ // об'єкт (File), що цікавить нас, зберігається у властивості "files" об'єкта "DataTransfer // вилучаємо його file = ev.dataTransfer.files[0] // перевіряємо log(file) /* File lastModified: 1593246425244 lastModifiedDate: Sat Jun 27 2020 13:27:05 GMT+0500 (Екатер name: "image.png" size: 208474 type: "image/png" webkitRelativePath: "" __proto__: File */ // передаємо файл у функцію для подальшої обробки handleFile(file) >)

Ми тільки-но реалізували найпростіший механізм «dran'n'drop».

Обробляємо клік файлоприймачем (делегуємо клік інпуту):

dropZone.addEventListener('click', () => < // натискаємо на прихований інпут input.click() // обробляємо зміну інпуту input.addEventListener('change', () => < // дивимося на те, що отримуємо log(input.files) // отримуємо наступне (у разі передачі зображення) /* FileList => 0: File lastModified: 1593246425244 lastModifiedDate: Sat Jun 27 2020 13:27:05 GMT+0500 (Єкатеринбург, стандартний : "image.png" size: 208474 type: "image/png" webkitRelativePath: "" __proto__: File length: 1 __proto__: FileList */ // вилучаємо File file = input.files[0] // перевіряємо log(file) // передаємо файл у функцію для подальшої обробки handleFile(file) >) >)

Приступаємо до обробки файлу:

const handleFile = file => < // подальші міркування >

Видаляємо файлоприймач та інпут:

dropZone.remove() input.remove()

Спосіб обробки файлу залежить від його типу:

log(file.type) // у разі зображення // image/png

Ми не будемо працювати з html, css та js-файлами, тому забороняємо їх обробку:

if (file.type === 'text/html' || file.type === 'text/css' || file.type === 'text/javascript') return;

Ми також не будемо працювати з MS-файлами (мають MIME-тип «application/msword», «application/vnd.ms-excel» тощо), оскільки їх неможливо обробити нативними засобами. Всі способи обробки таких файлів, що пропонуються на StackOverflow та інших ресурсах, зводяться або до конвертації в інші формати за допомогою різних бібліотек, або до використання viewer'ів від Google та Microsoft, які не хочуть працювати з файловою системою та localhost. Разом з тим тип pdf-файлів також починається з «application», тому такі файли ми будемо обробляти окремо:

if (file.type === 'application/pdf')

Для інших файлів отримуємо їх «груповий» тип:

// нас цікавить те, що знаходиться до сліша const type = file.type.replace(/\/.+/, '') // перевіряємо log(type) // у разі зображення // image

За допомогою switch..case визначаємо конкретну функцію обробки файлу:

switch (type) < // якщо зображення case 'image': createImage(file) break; // якщо аудіо case 'audio': createAudio(file) break; // якщо відео case 'video': createVideo(file) break; //якщо текст case 'text': createText(file) break; // інакше, виводимо повідомлення про невідомий формат файлу, // і за дві секунди перезавантажуємо сторінку default: B.innerHTML = `

Unknown File Format!

` const timer = setTimeout(() => < location.reload() clearTimeout(timer) >, 2000) break; >

Функція обробки зображення:

const createImage = image => < // створюємо елемент "img" const imageEl = D.createElement('img') // прив'язуємо його до отриманого зображення imageEl.src = URL.createObjectURL(image) // перевіряємо log(imageEl) / / поміщаємо документ B.append(imageEl) // видаляємо посилання на файл URL.revokeObjectURL(image) >

Функція обробки аудіо:

const createAudio = audio => < // створюємо елемент "audio" const audioEl = D.createElement('audio') // додаємо панель управління audioEl.setAttribute('controls', '') // прив'язуємо елемент до отриманого файлу audioEl. src = URL.createObjectURL(audio) // перевіряємо log(audioEl) // поміщаємо документ B.append(audioEl) // запускаємо відтворення audioEl.play() // видаляємо посилання на файл URL.revokeObjectURL(audio) >

Функція обробки відео:

const createVideo = video => < // створюємо елемент "video" const videoEl = D.createElement('video') // додаємо панель управління videoEl.setAttribute('controls', '') // зациклюємо відтворення videoEl.setAttribute(' loop', 'true') // прив'язуємо елемент до отриманого файлу videoEl.src = URL.createObjectURL(video) // перевіряємо log(videoEl) // поміщаємо документ B.append(videoEl) // запускаємо відтворення videoEl.play( ) // видаляємо посилання на файл URL.revokeObjectURL(video) >

Функція обробки тексту:

const createText = text => < // створюємо екземпляр об'єкта "FileReader" reader.readAsText(text, 'windows-1251') // очікуємо завершення читання файлу // і поміщаємо результат у документ reader.onload = () =>B.innerHTML = `

$

` >

Last, but not least, функція обробки PDF-файлів:

const createIframe = pdf => < // створюємо елемент "iframe" const iframe = D.createElement('iframe') // прив'язуємо його до отриманого файлу iframe.src = URL.createObjectURL(pdf) // збільшуємо розміри кадру до ширини та висоти області перегляду iframe.width = innerWidth iframe.height = innerHeight // перевіряємо log(iframe) // поміщаємо документ B.append(iframe) // видаляємо посилання на файл URL.revokeObjectURL(pdf) >

Створюємо JSON-файл

Для другого проекту створимо папку Create-JSON в кореневій директорії (Work-With-Files-in-JavaScript).

Створюємо файл "index.html" наступного змісту:


Create JSON

Create JSON

:

:

:

cloudget data

Для стилізації використовується Materialize.

Додаємо пару своїх стилів:

body < max-width: 512px; margin: 0 auto; text-align: center; >input <text-align: center; >.get-data

JSON-файли мають наступний формат:

Непарні інпути з типом "text" - ключі, парні - значення. Привласнюємо інпутам значення за умовчанням (значення можуть бути будь-якими). Кнопка з класом create-json служить для отримання значень, введених користувачем, і створення файлу. Кнопка із класів «get-data» — для отримання даних.

Переходимо до скрипту:

// знаходимо кнопку з класом "create-json" і обробляємо натискання цієї кнопки document.querySelector('.create-json'). замовчуванням, тобто.служить для відправки форми на сервер // відправлення форми тягне за собою перезавантаження сторінки // нам це не потрібно, тому відключаємо стандартну поведінку ev.preventDefault() // знаходимо всі інпути значення, введені користувачем // це можна зробити різними способами // такий спосіб здався мені найбільш оптимальним // тут ми реалізуємо щось схоже на метод "chunk" бібліотеки "lodash" // значення непарних інпутів (першого, третього та п'ятого) - ключі / / поміщаємо їх у підмасиви як перші елементи // значення парних інпутів (другого, четвертого і шостого) - значення // поміщаємо їх у підмасиви як другі елементи const arr = [] for (let i = 0; i < inputs.length ; ++i) < arr.push([inputs[i].value, inputs[++i].value]) >// отримуємо масив, що складається з трьох підмасивів console.log(arr) /* [ ["1", "foo"] ["2", "bar"] ["3", "baz"] ] */ // перетворимо масив підмасивів на об'єкт const data = Object .fromEntries(arr) // перевіряємо console.log(data) /* < 1: "foo" 2: "bar" 3: "baz" >*/ // створюємо файл const file = new Blob( // серіалізуємо дані [ JSON.stringify(data)], < type: 'application/json' >) // перевіряємо console.log(file) /* < "1": "foo", "2": "bar", "3": "baz" >*/ // те, що лікар прописав // створюємо елемент "a" const link = document.createElement('a') // прив'язуємо атрибут "href" тега "a" до створеного файлу link.setAttribute(' href', URL.createObjectURL(file)) // атрибут "download" дозволяє завантажувати файли, на які вказує посилання // значення цього атрибута - назва файлу, що скачується link.setAttribute('download', 'data.json') // текстовий вміст посилання link .textContent = 'DOWNLOAD DATA' // поміщаємо елемент у контейнер з класом "main" document.querySelector('.main').append(link) // видаляємо посилання на файл URL.revokeObjectURL(file) // < once: true >автоматично видаляє обробник після першого використання // повторний клік призводить до перезавантаження сторінки >, <once: true >)

По кліку на кнопці "CREATE JSON" формується файл "data.json", з'являється посилання "DOWNLOAD DATA" для завантаження цього файлу.

Що ми можемо зробити з цим файлом? Завантажуємо його і поміщаємо в папку Create-JSON.

// знаходимо кнопку (яка насправді посилання) з класом "get-data" і обробляємо її натискання document.querySelector('.get-data').addEventListener('click', () => < // за допомогою IIFE і async..await отримуємо дані та виводимо їх у консоль у вигляді таблиці (async() =>< const response = await fetch('data.json') // розбираємо (парсим) відповідь const data = await response.json() console.table(data) >)() >)

Створюємо генератор питань та тестер

Генератор питань

Для третього проекту створимо папку Test-Maker у кореневій директорії.

Створюємо файл «createTest.html» наступного змісту:


Create Test




Answers:



Explanation:


На цей раз для стилізації використовується Bootstrap. Ми не використовуємо атрибути «required», оскільки валідуватимемо форму в JS (з required поведінка форми, що складається з декількох обов'язкових полів, стає дратівливою).

Додаємо пару своїх стилів:

body < max-width: 512px; margin: 0 auto; text-align: center; >input[type="radio"]

Ми маємо шаблон питання. Пропоную винести його в окремий файл для використання як компонент за допомогою динамічного імпорту. Створюємо файл «Question.js» такого змісту:

export default (name = Date.now()) => ` 



Answers:

">
">
">


Explanation:

`

Тут у нас все те саме, що й у createTest.html, за винятком того, що ми прибрали значення за умовчанням для інпутів і передаємо аргумент «name» як значення однойменного атрибуту (даний атрибут має бути унікальним для кожного питання — це дає можливість перемикати варіанти відповідей, вибирати одну з кількох).Значенням name за умовчанням є час у мілісекундах, що минув з 1 січня 1970 року, - проста альтернатива генераторам випадкових значень типу Nanoid, що використовуються для отримання унікального ідентифікатора (навряд чи користувач встигне створити два питання за 1 мс).

Переходимо до основного скрипту.

Я маю намір створити кілька допоміжних (фабричних) функцій, але це не обов'язково.

// функція знаходження одного елемента із зазначеним селектором const findOne = (element, selector) => element.querySelector(selector) // функція знаходження всіх елементів із зазначеним селектором const findAll = (element, selector) => element.querySelectorAll(selector) // функція додавання обробника зазначеної події const addHandler = (element, event, callback) => element.addEventListener(event, callback) // функція знаходження батьківських елементів // однією з проблем Bootstrap є глибока вкладеність елементів // при роботі з DOM часто виникає необхідність звернення до батька цільового елемента // наша функція приймає два аргументи - елемент і глибину (вкладення), // яка за умовчанням дорівнює 1 const findParent = (element, depth = 1) => < // якщо елемент знаходиться на першому рівні вкладеності // означає, нам потрібен його батьківський елемент let parentEl = element.parentElement // інакше, ми шукаємо батька батька та ін. за допомогою рекурсії while (depth >1) < // рекурсія parentEl = findParent(parentEl) // зменшуємо значення глибини depth-- >// повертаємо шуканий елемент return parentEl >

У нашому випадку у пошуках батьківського елементу ми дійдемо до третього рівня вкладеності. Оскільки ми знаємо точну кількість цих рівнів, ми могли б використовувати if..else if або switch..case, однак варіант з рекурсією є більш універсальним.

Ще раз: вводити фабричні функції не обов'язково, ви можете обійтися стандартним функціоналом.

Знаходимо основний контейнер та контейнер для питань, а також відключаємо відправку форми:

const C = findOne(document.body, '.container') // const C = document.body.querySelector('.container') const Q = findOne(C, '#questions-box') addHandler(Q, 'submit ', ev => ev.preventDefault()) // Q.addEventListener('submit', ev => ev.preventDefault())

Функція ініціалізації кнопок видалення питання:

// функція приймає питання як аргумент const initRemoveQuestionBtn = q => < const removeQuestionBtn = findOne(q, '.remove-question-btn') addHandler(removeQuestionBtn, 'click', ev => < // видаляємо батька * => 


=>
=>
. */ findParent(ev.target, 2).remove() // ev.target.parentElement.parentElement.remove() // при видаленні питання необхідно оновити номери питань initTitles() >, < // видаляємо обробник після використання once: true >) >

Функція ініціалізації кнопок видалення варіанта відповіді:

const initRemoveAnswerBtns = q => < const removeAnswerBtns = findAll(q, '.remove-answer-btn') // const removeAnswerBtns = q.querySelectorAll('.remove-answer-btn') removeAnswerBtns.forEach btn, 'click', ev => < /* => 
. =>
=>
*/ findParent(ev.target, 2).remove() >, < once: true >)) >

Функція ініціалізації кнопок для додавання варіанта відповіді:

const initAddAnswerBtns = q => < const addAnswerBtns = findAll(q, '.add-answer-btn') addAnswerBtns.forEach(btn =>addHandler(btn, 'click', ev => < // знаходимо контейнер для відповідей const ) = findOne(findParent(ev.target), '.answers-box') // const answers = ev.target.parentElement.querySelector('.answers-box') // атрибут "name" повинен бути унікальним для кожного питання let name answers.children.length >0 ? name = findOne(answers, 'input[type="radio"]').name : name = Date.now() // шаблон варіанта відповіді const template = ` 
">
` // поміщаємо шаблон до кінця контейнера для відповідей answers.insertAdjacentHTML('beforeend', template) // ініціалізуємо кнопки для видалення варіантів відповіді initRemoveAnswerBtns(q) >)) >

Поєднуємо функції ініціалізації кнопок в одну:

Функція ініціалізації заголовків питань:

Ініціалізуємо кнопки та заголовок питання:

initBtns(findOne(Q, '.question-box')) initTitles()

Функція додавання запитання:

// знаходимо кнопку const addQuestionBtn = findOne(C, '#add-question-btn') addHandler(addQuestionBtn, 'click', ev => < // за допомогою IIFE та async..await отримуємо дані за допомогою динамічного імпорту // поміщаємо їх у контейнер для питань // знаходимо додане питання // та ініціалізуємо кнопки цього питання та всі заголовки (async() =>< const data = await import('./Question.js') const template = await data.default() await Q.insertAdjacentHTML('beforeend', template) const question = findOne(Q, '.question-box:last-child') initBtns(question) initTitles() >)() >)

Функція створення тесту:

// обробляємо клік по кнопці для створення тесту addHandler(findOne(C, '#create-test-btn'), 'click', () => createTest()) const createTest = () => < // створюємо порожній об'єкт const obj = <>// знаходимо всі питання const questions = findAll(Q, '.question-box') // проста функція валідації форми // поля не повинні бути порожніми const isEmpty = (. args) => < // для кожного переданого аргументу args.map(arg => < // замінюємо два і більше пробіли на один // і видаляємо прогалини на початку та в кінці рядка arg = arg.replace(/\s+/g, '').trim() / / якщо значенням аргументу є порожній рядок if (arg === '') < // повідомляємо про це користувачеві alert('Some field is empty!') // і викидаємо виняток throw new Error() >>) > // для кожного питання questions.forEach(q => < // текст питання const questionText = findOne(q, '.question-text').value // створюємо масив для варіантів відповіді // кількість варіантів може бути будь-яким const answersText = [] findAll (q, '.answer-text'). "checked" інпут з класом "answer-text" /* => 
=>
=>. */ const rightAnswerText = findOne(findParent(findOne(q, 'input:checked'), 3), '.answer-text').value // текст пояснення const explanationText = findOne(q, '.explanation-text') .value // валідуємо форму isEmpty(questionText, . answersText, explanationText) // поміщаємо значення в об'єкт з ключем "індекс питання" obj[questions.indexOf(q)] = < question: questionText, answers: answersText, rightAnswer: rightAnswerText, explanation: explanationText >>) // перевіряємо console.table(obj) // створюємо файл const data = new Blob( [JSON.stringify(obj)], < type: 'application/json' >) // якщо файл вже створено // видаляємо посилання if (findOne(C, 'a') !== null) < findOne(C, 'a').remove() >// за старою схемою const link = document.createElement('a') link.setAttribute('href', URL.createObjectURL(data)) link.setAttribute('download', 'data.json') link.className = 'btn btn -success' link.textContent = 'Download data' C.append(link) URL.revokeObjectURL(data) >
Використовуємо дані із файлу

За допомогою генератора питань створимо такий файл:

Поміщаємо цей файл (data.json) у папку Test-Maker.

Створюємо файл "useData.html" наступного змісту:

Додаємо пару своїх стилів:

body < max-width: 512px; margin: 0 auto; text-align: center; >section *:not(h3) < text-align: left; >input, button < margin: .4em; >label, input < cursor: pointer; >.right-answer, .explanation
// функція отримання даних const getData = async url => < const response = await fetch(url) const data = await response.json() return data >// отримуємо дані getData('data.json') .then(data = > < // перевіряємо console.table(data) // передаємо дані функції створення тесту createTest(data) >) // генеруємо значення name let name = Date.now() // функція створення тесту const createTest = data => < / / data - це об'єкт з об'єктів // для кожного об'єкта for (const item in data) < // перевіряємо console.log(data[item]) // деструктуруємо об'єкт, // отримуємо значення питання, варіантів відповіді, правильної відповіді та пояснення const < question, answers, rightAnswer, explanation >= data[item] // робимо значення name унікальним для кожного питання name++ // шаблон питання const questionTemplate = ` 

Question $: $
Answers $ html += ``>$
`, '')>

Right answer: $

Explanation: $

// поміщаємо шаблон в кінець документа document.body.insertAdjacentHTML('beforeend', questionTemplate) >) // знаходимо питання const forms = document.querySelectorAll('form') // вибираємо перші варіанти відповіді на всі питання forms.forEach( form => < const input = form.querySelector('input') input.click() >) // створюємо кнопку для перевірки відповідей // і поміщаємо її в кінець документа const btn = document.createElement('button') btn.className = 'btn btn-primary' btn.textContent = 'Check answers' document.body.append(btn) // обробляємо натискання цієї кнопки btn.addEventListener('click', () => < // створюємо масив для відповідей const answers = [] // для кожного питання forms.forEach(form =>< // отримуємо значення вибраної (користувацької) відповіді const chosenAnswer = form.querySelector('input:checked'). parentElement.textContent // отримуємо значення правильної відповіді const rightAnswer = form.nextElementSibling.textContent.replace('Right answer: ', '') // додаємо ці значення до масиву у вигляді підмасиву answers.push([chosenAnswer, rightAnswer]) >) console.log(answers) // отримуємо наступне / / у випадку, коли відповідь на третє питання неправильна /* Array(3) 0: (2) ["foo", "foo"] 1: (2) ["bar", "bar"] 2: (2) ["foo", "baz"] */ // передаємо масив функції checkAnswers(answers) >) // функція перевірки ( порівняння) відповідей const checkAnswers = answers => < // лічильники для кількості правильних та неправильних відповідей let rightAnswers = 0 let wrongAnswers = 0 // для кожного підмасиву, // де перший елемент - вибраний (користувацька) відповідь, // а другий елемент - правильна відповідь for (const answer of answers) < // якщо вибраний і правильний відповіді збігаються if (answer[0 ] === answer[1]) < // збільшуємо кількість правильних відповідей rightAnswers++ // інакше >else < // збільшуємо кількість неправильних відповідей відповідей wrongAnswers++ // знаходимо питання з неправильною відповіддю const wrongSection = forms[answers.indexOf(answer)].parentElement // показуємо правильну відповідь та поясненняwrongSection.querySelector('.right-answer').style.display = 'block' wrongSection.querySelector('.explanation').style.display = 'block' >> // визначаємо відсоток правильних відповідей const percent = parseInt(rightAnswers / answers.length * 100) // рядок-результат let result = '' // залежно від відсотка правильних відповідей // присвоюємо result відповідне значення if (percent >= 80) < result = 'Great job, super genius!' >else if (percent > 50) < result = 'Не погано, але ви можете зробити це!' >else < result = 'Very bad, try again!' >// шаблон результатів тесту const resultTemplate = `

Your result

Right answers: $

Wrong answers: $

Percentage of correct answers: $

$ ` // поміщаємо шаблон на кінець документа document.body.insertAdjacentHTML('beforeend', resultTemplate) > >

Результат (якщо відповідь на третє питання неправильна):

Бонус. Записуємо дані у CloudFlare

Заходимо на cloudflare.com, реєструємось, натискаємо на Workers праворуч, потім на кнопку Create a Worker.

Змінюємо назву воркера на data (це не обов'язково). У поле "<> Script" вставляємо наступний код і натискаємо на кнопку "Save and Deploy":

// обробляємо отриманий запит addEventListener('fetch', event => < event.respondWith( new Response( // наші дані `< "0": < "question": "first question", "answers": ["foo") , "bar", "baz"], "rightAnswer": "foo", "explanation": "first explanation" >, "1": < "question": "second question", "answers": ["foo" , "bar", "baz"], "rightAnswer": "bar", "explanation": "second explanation" >, "2": < "question": "third question", "answers": ["foo" , "bar", "baz"], "rightAnswer": "baz", "explanation": "third explanation" >>`, < status: 200, // спеціальний заголовок для подолання CORS headers: new Headers() >) ) >)


Тепер ми можемо отримувати дані із CloudFlare. Для цього достатньо вказати URL воркера замість 'data.json' у функції getData. У моєму випадку це виглядає так: getData('https://data.aio350.workers.dev/').then(. ).

Довга стаття вийшла. Сподіваюся, Ви знайшли в ній щось корисне.

Дякую за увагу.

  • javascript
  • програмування
  • розробка
  • file system
  • file api
  • file reader
  • file upload
  • читання файлів
  • завантаження файлів
  • обробка файлів

Як прочитати вміст файлу

Як за допомогою JavaScript завантажити список слів із файлу в масив. Як я розумію прочитати безпосередньо файл не можна через налаштування безпеки. Як ще можна завантажити список слів?

1 відповідь 1

Можна! Без сервера!

За допомогою FileReader (посилання на MDN). Але, звичайно, з явного дозволу користувача (про це нижче). Ось приклад, за авторством шанованого (див. репутацію) Paolo Moretti, взятий з його відповіді:

function readSingleFile(e) < var file = e.target.files[0]; if (! file) < return; >var reader = новий FileReader(); reader.onload = function(e) < var contents = e.target.result; displayContents(contents); >; reader.readAsText(file); > function displayContents(contents) < var element = document.getElementById('file-content'); element.innerHTML = contents; >document.getElementById('file-input') .addEventListener('change', readSingleFile, false);

Звичайно, є певні обмеження на те, які файли можна відкривати. На даний момент є два способи (для користувача) дати доступ до файлу:

File та FileReader

Об'єкт File успадковується від об'єкта Blob і має можливості взаємодії з файловою системою.

Є два способи отримати.

По-перше, є конструктор, схожий на Blob:

new File(fileParts, fileName, [options])
  • fileParts - Масив значень Blob / BufferSource / рядки.
  • fileName - Ім'я файлу, рядок.
  • options - Необов'язковий об'єкт із властивістю:
    • lastModified - Дата останньої зміни у форматі таймстамп (ціле число).

    По-друге, найчастіше ми отримуємо файл або через перетягування за допомогою миші, або з інших інтерфейсів браузера. У цьому випадку файл отримує цю інформацію з операційної системи.

    Так як File успадковує від Blob , об'єкти File мають ті ж властивості плюс:

    • name – ім'я файлу,
    • lastModified – таймстамп для дати останньої зміни.

    У цьому прикладі ми отримуємо об'єкт File з:

    
    
    

    Можна вибрати кілька файлів, тому input.files - псевдомасив вибраних файлів. Тут ми маємо лише один файл, тому ми просто беремо input.files[0] .

    FileReader

    FileReader об'єкт, мета якого читати дані з Blob (і, отже, з File теж).

    Дані передаються за допомогою подій, оскільки читання з диска може тривати час.

    let reader = новий 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 – читання завершено (успішно чи ні).

    Коли читання закінчено, ми зможемо отримати доступ до його результату таким чином:

    • reader.result результат читання (якщо воно успішне)
    • reader.error об'єкт помилки (при невдачі).

    Найчастіше використовувані події - це, звичайно ж, 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 .

Схожі статті

  • Як прочитати один рядок з файлу з
  • Скільки ставити файл підкачування на 4 Гб оперативної пам'яті
  • Навіщо використовують файл
  • Як зробити файл підкачки на Windows 10
  • Як перейменувати файл в асемблері
  • Що таке файл на комп'ютері
  • Як видалити файли на телефоні
  • Як створити файл XSL
  • Недавні статті

  • Як бродить зернова брага
  • Що робити якщо не засмагаєш на сонці чому засмага погано лягає на шкіру або перестає прилипати
  • Як швидко зняти гель лак без апарату
  • Як робиться Каті голови
  • Яка гребінець краще для об'єму
  • Чим роблять м'яку покрівлю
  • Чи можна залишати крем для обличчя на ніч
  • Де знаходиться датчик селектора
  • географія нашої діяльності
    вулиця Драгоманова, 27
    вул. Курчатова 1Б
    вул. Міцкевича 130
    вул. Лабунського, 1
    вул. Макарова-Пржевальського
    вул. Толстого 10
    вул. Грушевського 28
    вул. Перший промінь (Черняхівського)
    напишіть нам

    сообщение успешно отправлено
    x