API FileReader у HTML5 дозволяє клієнтському браузеру читати локальні файли користувача, тож завантажений файл більше не читається сервером, що значно зменшує навантаження на сервер і економить час, необхідний для завантаження файлу. Однак на практиці я виявив, що можу легко обробляти файл журналу 300k за допомогою FileReader.readAsText(), але коли файл журналу такий великий, як 1G або навіть 2G, браузер починає зависати. Це пов'язано з тим, що readAsText() завантажує цільовий файл у пам'ять одночасно, через що пам'ять перевищує ліміт. Тож якщо веб-додаток часто потребує обробки великих файлів, слід використовувати FileReader.readAsArrayBuffer() для читання файлів по частинах.
Тестовий сценарій
Наш сценарій простий — використовувати JavaScript для отримання часового діапазону журналу IIS
Приклади журналів IIS:
#Software: Microsoft Internet Information Services 10.0 #Version: 1.0 #Date: 2016-08-18 06:53:55 #Fields: дата час s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken 2016-08-18 06:53:55 ::1 GET / - 80 - ::1 Mozilla/5.0+(Windows+NT+10.0; +WOW64; +Trident/7.0; +rv:11.0)+like+Gecko - 200 0 0 476 2016-08-18 06:53:55 ::1 GET /iisstart.png - 80 - ::1 Mozilla/5.0+(Windows+NT+10.0; +WOW64; +Trident/7.0; +rv:11.0)+like+Gecko http://localhost/ 200 0 0 3 2016-08-18 08:45:34 10.172.19.198 GET /test/pac/wpad.dat - 80 - 10.157.21.235 Mozilla/5.0+(Windows+NT+6.1; +Win64; +x64; +Trident/7.0; +rv:11.0)+like+Gecko - 404 3 50 265 2016-08-18 08:46:44 10.172.19.198 GET /test/pac/wpad.dat - 80 - 10.157.21.235 Mozilla/5.0+(Windows+NT+6.1; +Win64; +x64; +Trident/7.0; +rv:11.0)+like+Gecko - 200 0 0 6 Наша мета — отримати часові рамки цього журналу:
Час початку: 2016-08-18 06:53:55 Кінець: 2016-08-18 08:46:44
Використовуйте реалізацію readAsText()
Використання readAsText() досить просто: після отримання рядка всього файлу отримати перші 19 символів кожного рядка з початку, визначити, чи відповідає формат дати, якщо він задовольняє, то ці 19 символів — це час початку, і те саме проходить через кожен рядок від хвоста для отримання кінцевого часу, код виглядає так:
Поточні результати вибіркового журналу IIS (розмір: 1k) відповідають очікуванням.
Але як тільки ми оберемоБільший журнал IIS (розмір: 2G) — і браузер вилітає。 Причина в тому, що readAsText() спочатку завантажує весь файл у пам'ять, тому якщо файл занадто великий, пам'яті не вистачить, і браузерний процес може зависати.
Використання реалізації readAsArrayBuffer()
Оскільки об'єкт File у JavaScript успадковує від Blob, ми можемо використати метод Blob.slice() для розрізання файлу на дрібні частини, загальна ідея така:
Спочатку візьміть перші 10k вмісту файлу і конвертуйте їх у текст Візьміть перші 19 символів кожного рядка з початку, щоб визначити, чи відповідає формату дати, і якщо так, то ці 19 символів — час початку Потім візьміть 10k контент у кінці файлу і конвертуйте його у текст Аналогічно, пройдіть кожну лінію від вмісту хвоста, щоб отримати кінцевий час
Код виглядає так:
Використовуючи readAsArrayBuffer(), ми змогли отримати бажані результати за дуже короткий час, навіть маючи більше ніж 2G IIS-логів.
|