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() для разрезания файла на мелкие части, общая идея такова:
Сначала возьмите первые 10 тысяч содержимого файла и конвертируйте их в текст Возьмём первые 19 символов каждой строки с самого начала, чтобы определить, соответствует ли формату даты, и если да, то эти 19 символов — это время начала Затем возьмите 10 тысяч контента в конце файла и конвертируйте его в текст Аналогично, пройдите каждую строку от содержимого хвоста, чтобы получить конечное время
Код таков:
Используя readAsArrayBuffer(), мы смогли получить нужные результаты за очень короткое время, даже при большем количестве 2G IIS-логов.
|