A API FileReader do HTML5 permite que o navegador cliente leia os arquivos locais do usuário, de modo que o arquivo enviado não seja mais lido pelo servidor, o que reduz muito a carga sobre o servidor e economiza o tempo necessário para enviar o arquivo. No entanto, na prática, percebi que consigo lidar facilmente com um arquivo de log de 300k com o FileReader.readAsText(), mas quando o arquivo de log é de tamanho de 1G ou até 2G, o navegador trava. Isso ocorre porque readAsText() carrega o arquivo alvo na memória de uma vez só, fazendo com que a memória ultrapasse o limite. Então, se a aplicação web frequentemente precisa processar arquivos grandes, devemos usar o FileReader.readAsArrayBuffer() para ler os arquivos pedaço por pedaço.
Cenário de teste
Nosso cenário é simples, que é usar JavaScript para obter o intervalo de tempo de um log IIS
Logs de exemplo do IIS:
#Software: Microsoft Internet Information Services 10.0 #Version: 1.0 #Date: 18-08-2016 06:53:55 #Fields: data hora s-ip cs-método cs-uri-stem cs-uri-query s-porta cs-nome de usuário 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; +Tridente/7.0; +RV:11.0)+Tipo+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; +Tridente/7.0; +rv:11.0)+tipo+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; +Tridente/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; +Tridente/7.0; +rv:11.0)+like+Gecko - 200 0 0 6 Nosso objetivo é obter o período de tempo desse registro:
Horário de início: 2016-08-18 06:53:55 Horário final: 2016-08-18 08:46:44
Use a implementação readAsText()
Usar readAsText() é relativamente simples, depois de obter a string de todo o arquivo, obtenha os primeiros 19 caracteres de cada linha desde o início, determine se o formato de data é cumprido, se for satisfeito, então esses 19 caracteres são o horário de início, e o mesmo passa por cada linha a partir da cauda para obter o horário final, o código é o seguinte:
Os resultados executantes do log amostral do IIS (tamanho: 1k) são os que esperávamos.
Mas uma vez que escolhemosUm log IIS maior (tamanho: 2G) e o navegador trava。 O motivo é que readAsText() carrega o arquivo inteiro na memória primeiro, então se o arquivo for muito grande, não haverá memória suficiente e o processo do navegador trava.
Use a implementação readAsArrayBuffer()
Como o objeto Arquivo em JavaScript herda do Blob, podemos usar o método Blob.slice() para cortar o arquivo em pequenos pedaços, a ideia geral é:
Primeiro, pegue os primeiros 10 mil conteúdos do arquivo e converta em texto Pegue os primeiros 19 caracteres de cada linha do início para determinar se o formato de data é cumprido e, se sim, esses 19 caracteres são o horário de início Depois, pegue o conteúdo de 10k no final do arquivo e converta em texto Da mesma forma, percorra cada linha a partir do conteúdo da cauda para obter o tempo final
O código é o seguinte:
Usando readAsArrayBuffer(), conseguimos obter os resultados que queríamos em muito pouco tempo, mesmo com mais de 2G de logs IIS.
|