Situação
Digamos que o usuário pode carregar um arquivo em uma página da web, que geralmente é de tamanho grande (mínimo de 80 MB, pode ser muito mais) e de um tipo específico, digamos, por exemplo , PDF.
Considerando que esses são arquivos enormes, não gostaríamos de desperdiçar largura de banda desnecessariamente carregando o arquivo apenas para perceber que o tipo do arquivo está errado. Portanto, gostaríamos de ter certeza, no lado do cliente, de que o arquivo é realmente um arquivo PDF, e somente ENTÃO enviá-lo se realmente for.
Felizmente, o formato de arquivo PDF tem um número mágico de 5 bytes , igual a 25 50 44 46 2D
.
(É um exemplo , pode ser qualquer formato de arquivo, estou usando PDF como referência. O que importa é que é um formato de arquivo que você pode diferenciar com seus bytes mágicos, o que consideramos uma verificação boa o suficiente aqui. Além disso, minha pergunta pode ser relevante para outros casos, não apenas este exemplo de formato de arquivo, por favor, considere o exemplo PDF apenas como uma forma de dar um exemplo prático sobre o problema)
Daí minha pergunta: como eu leria os 5 primeiros bytes do arquivo ou, mais genericamente, os primeiros N bytes de um arquivo?
Você não gostaria de ler o arquivo inteiro, já que ele pode ser enorme e o disco rígido do cliente pode ser lento. Você só precisa ler esses cinco bytes e, somente se eles estiverem corretos, você lerá o restante do arquivo para enviá-lo ao servidor.
Se não houver uma maneira, há alguma solução alternativa ou proposta em andamento para esse recurso?
O que eu tentei
A FileReader
API permite ler um arquivo em um buffer de matriz (veja esta resposta e a documentação ):
let reader = new FileReader();
reader.onload = function() {
let arrayBuffer = this.result,
array = new Uint8Array(arrayBuffer),
binaryString = String.fromCharCode.apply(null, array);
console.log(binaryString);
}
reader.readAsArrayBuffer(this.files[0]);
No entanto, isso lê o arquivo inteiro.
Perguntas semelhantes que não dão solução para minha pergunta
- Você consegue ler linha por linha em javascript? A resposta aceita de depende de alguma API externa.
- Existe uma maneira de obter partes específicas de um arquivo com FileReader em JavaScript? solicitado a ler de acordo com um caractere específico repetido no arquivo, o que obviamente não era possível sem ler o arquivo inteiro primeiro
- Todas as perguntas relacionadas ao NodeJS: Estou fazendo isso em um navegador da web, qualquer proposta que não seja de navegador não é uma solução
Comentários
(Respondendo a comentários significativos aqui, já que os comentários são temporários )
O fatiamento do arquivo real em si ajuda? https://stackoverflow.com/a/24845020/1427878 – @C3roe
Ele me dá o resultado esperado, mas qual é a garantia de que ele realmente lê apenas os primeiros n bytes e não lê tudo e depois fatia? Há algum detalhe de implementação para isso nos padrões? O MDN afirma: "a new Blob object which contains data from a subset of the blob on which it's called."
, o que implica que havia um blob completo para fatiar em primeiro lugar.
Não há problema em usar a tag HTML . Atualmente, ela é um ponteiro para o arquivo local real.
A chave para ler somente o slice está presente na questão anterior. Mas acredito que vale a pena mostrar todas as restrições da questão relacionada:
Obter o arquivo do ouvinte de evento fileEvent change
Em seguida, use as seguintes funções, usando seu leitor.
Em seguida, teste com sua sequência mágica (pode ser um número ou não)
Confie que isso ajuda.
No Javascript do lado do cliente, um
File
objeto representa um arquivo no sistema de arquivos local. Ele não lê o arquivo imediatamente na memória do navegador. A leitura seria uma operação assíncrona, enquanto aFile
pode ser construído de forma síncrona.File
é uma subclasseBlob
cujoslice
método produz outroBlob
(novamente, de forma síncrona) que representa um subconjunto de bytes contíguos do arquivo (novamente, sem lê-los).Na verdade, ler o conteúdo do arquivo ou do slice requer a invocação do método assíncrono
text
(oubytes
métodos ouarrayBuffer
), ou o uso de umReadableStream
obtido viastream
método. Todos esses métodos introduzem assincronia.Portanto, é possível usar pequenas fatias de um arquivo
Não é possível usar HTML
<input type="file">
sozinho. O arquivo inteiro é sempre lido.É possível usar uma
fetch()
solicitação com cabeçalho de intervalo definido - e uma extensão da Web onde o usuário podefetch()
file:
protocolar; ou iniciar um servidor local parafetch()
o arquivo com cabeçalho de intervalo; ou usar o Native Messaging com uma extensão, nesse caso você pode fazer o que quiser usando o aplicativo local na máquina do usuário.Agora, se você quiser apenas ler os primeiros N bytes do
File
objeto completo