API FileReader HTML5 pozwala przeglądarce klienta odczytywać lokalne pliki użytkownika, dzięki czemu przesłany plik nie jest już odczytywany przez serwer, co znacznie zmniejsza obciążenie serwera i oszczędza czas potrzebny na przesłanie pliku. Jednak w praktyce zauważyłem, że łatwo obsługuję plik logowy o wartości 300k za pomocą FileReader.readAsText(), ale gdy plik logu jest tak duży jak 1G lub nawet 2G, przeglądarka się zawiesza. Dzieje się tak, ponieważ readAsText() ładuje plik docelowy do pamięci jednocześnie, powodując przekroczenie limitu pamięci. Jeśli więc aplikacja webowa często musi przetwarzać duże pliki, powinniśmy użyć FileReader.readAsArrayBuffer() do odczytywania plików kawałek po kawałku.
Scenariusz testowy
Nasz scenariusz jest prosty – użycie JavaScript do uzyskania zakresu czasowego logu IIS
Przykładowe logi IIS:
#Software: Microsoft Internet Information Services 10.0 #Version: 1.0 #Date: 2016-08-18 06:53:55 #Fields: data time 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 Naszym celem jest uzyskanie ram czasowych tego dziennika:
Godzina rozpoczęcia: 2016-08-18 06:53:55 Czas zakończenia: 2016-08-18 08:46:44
Użyj implementacji readAsText()
Używając readAsText() jest to stosunkowo proste: po uzyskaniu ciągu całego pliku pobierasz pierwsze 19 znaków każdej linii od początku, określasz, czy format daty jest spełniony, jeśli jest spełniony, te 19 znaków to czas rozpoczęcia, a to samo przechodzi przez każdą linię od końca, aby uzyskać czas zakończenia, kod wygląda następująco:
Wyniki testu logu IIS (rozmiar: 1k) są zgodne z naszymi oczekiwaniami.
Ale gdy już wybierzemyWiększy log IIS (rozmiar: 2G) i przeglądarka się zawiesza。 Powód jest taki, że readAsText() najpierw załaduje cały plik do pamięci, więc jeśli plik jest zbyt duży, nie będzie wystarczająco dużo pamięci i proces przeglądarki się zawiesi.
Użyj implementacji readAsArrayBuffer()
Ponieważ obiekt File w JavaScript dziedziczy z Blob, możemy użyć metody Blob.slice() do pocięcia pliku na małe kawałki, ogólna idea jest następująca:
Najpierw weź pierwsze 10 tys. zawartości pliku i przekonwertuj je na tekst Weź pierwsze 19 znaków każdej linii od początku, aby określić, czy format daty jest spełniony, a jeśli tak, to te 19 znaków to czas rozpoczęcia Następnie weź zawartość 10k na końcu pliku i przekonwertuj ją na tekst Podobnie, przebiegaj każdą linię od zawartości ogonowej, aby uzyskać czas końcowy
Kod jest następujący:
Korzystając z readAsArrayBuffer(), udało nam się uzyskać oczekiwane wyniki w bardzo krótkim czasie, nawet przy ponad 2G logach IIS.
|