Selecionar e interagir com arquivos no dispositivo local do usuário é um dos recursos da Web mais usados. Ele permite que os usuários selecionem arquivos e façam upload deles para um servidor, por exemplo, ao compartilhar fotos ou enviar documentos fiscal. Além disso, os sites podem ler e manipular essas informações sem precisar transferir os dados pela rede. Nesta página, explicamos como usar o JavaScript para interagir com arquivos.
A moderna API File System Access
A API File System Access oferece uma maneira de ler e gravar arquivos e diretórios no sistema local do usuário. Ela está disponível na maioria dos navegadores baseados no Chromium, como o Chrome e o Edge. Para saber mais sobre isso, consulte API File System Access.
Como a API File System Access não é compatível com todos os navegadores, recomendamos o uso do browser-fs-access, uma biblioteca auxiliar que usa a nova API sempre que ela está disponível e usa as abordagens legadas quando ela não está disponível.
Trabalhe com arquivos do jeito clássico
Neste guia, mostramos como interagir com arquivos usando métodos JavaScript legados.
Selecionar arquivos
Há duas maneiras principais de selecionar arquivos: usando o elemento de entrada HTML e usando uma zona de arrastar e soltar.
Elemento de entrada HTML
A maneira mais fácil de selecionar arquivos é usando o elemento
<input type="file">
, que tem suporte em todos os principais navegadores. Quando clicado, ele permite que o usuário
selecione um arquivo ou vários arquivos se o atributo
multiple
estiver incluído, usando a interface integrada de seleção de arquivos
do sistema operacional. Quando o usuário termina de selecionar um ou mais arquivos, o evento change
do elemento é disparado. É possível acessar a lista de arquivos de event.target.files
, que
é um objeto FileList
.
Cada item em FileList
é um objeto File
.
<!-- The `multiple` attribute lets users select multiple files. -->
<input type="file" id="file-selector" multiple>
<script>
const fileSelector = document.getElementById('file-selector');
fileSelector.addEventListener('change', (event) => {
const fileList = event.target.files;
console.log(fileList);
});
</script>
O exemplo a seguir permite que um usuário selecione vários arquivos usando a IU de seleção de arquivos integrada do sistema operacional e, em seguida, registra cada arquivo selecionado no console.
Limitar os tipos de arquivos que os usuários podem selecionar
Em alguns casos, talvez você queira limitar os tipos de arquivo que os usuários podem selecionar. Por
exemplo, um app de edição de imagens precisa aceitar apenas imagens, não arquivos de texto. Para definir
restrições de tipo de arquivo, adicione um atributo
accept
ao elemento de entrada para especificar quais tipos são aceitos:
<input type="file" id="file-selector" accept=".jpg, .jpeg, .png">
Arrastar e soltar personalizado
Em alguns navegadores, o elemento <input type="file">
também é um destino de soltar,
permitindo que os usuários arrastem e soltem arquivos no seu app. No entanto, esse destino
é pequeno e pode ser difícil de usar. Em vez disso, depois de fornecer os recursos principais usando
um elemento <input type="file">
, você pode oferecer uma superfície grande e personalizada de arrastar
e soltar.
Escolha sua zona de coleta
A superfície de soltar depende do design do aplicativo. Você pode querer apenas que parte da janela seja uma superfície de soltar, mas pode usar a janela inteira.
![Captura de tela do Squoosh, um app da Web de compactação de imagens.](https://web.dev/static/articles/read-files/image/a-screenshot-squoosh-i-9973c866302e4.png?authuser=5&hl=pt-br)
O app de compactação de imagem Squoosh permite que o usuário arraste uma imagem para qualquer lugar da
janela e clique em selecionar uma imagem para invocar o elemento
<input type="file">
. Seja qual for sua zona de soltar, confira se está claro para o usuário
que ele pode arrastar arquivos para essa plataforma.
Definir a zona de descarte
Para ativar um elemento como uma zona de arrastar e soltar, crie listeners para
dois eventos: dragover
e drop
.
O evento dragover
atualiza a interface do navegador para indicar visualmente que a
ação de arrastar e soltar está criando uma cópia do arquivo. O evento drop
é disparado
depois que o usuário solta os arquivos na superfície. Assim como acontece com o elemento de entrada, você
pode acessar a lista de arquivos em event.dataTransfer.files
, que é um objeto
FileList
. Cada
item em FileList
é um objeto File
.
const dropArea = document.getElementById('drop-area');
dropArea.addEventListener('dragover', (event) => {
event.stopPropagation();
event.preventDefault();
// Style the drag-and-drop as a "copy file" operation.
event.dataTransfer.dropEffect = 'copy';
});
dropArea.addEventListener('drop', (event) => {
event.stopPropagation();
event.preventDefault();
const fileList = event.dataTransfer.files;
console.log(fileList);
});
event.stopPropagation()
e event.preventDefault()
interrompem o comportamento padrão do navegador e permitem a execução do código. Sem eles, o navegador sairia da sua página e abriria os arquivos que o usuário colocou na janela do navegador.
Para uma demonstração ao vivo, consulte Arrastar e soltar personalizado.
E os diretórios?
Infelizmente, não existe uma boa maneira de acessar um diretório usando JavaScript.
O atributo webkitdirectory
no elemento <input type="file">
permite que o usuário escolha um diretório
ou diretórios. Ela é compatível com a maioria dos principais navegadores,
exceto com o Firefox para Android e o Safari no iOS.
Se o recurso de arrastar e soltar estiver ativado, o usuário poderá tentar arrastar um diretório para a
zona de soltar. Quando o evento de soltar é disparado, ele inclui um objeto File
para o
diretório, mas não fornece acesso a nenhum dos arquivos nele.
Ler metadados de arquivos
O objeto File
contém metadados sobre o arquivo. A maioria dos navegadores fornece o nome do arquivo, o tamanho do arquivo e o tipo MIME. No entanto, dependendo da plataforma, diferentes navegadores podem fornecer informações diferentes ou adicionais.
function getMetadataForFileList(fileList) {
for (const file of fileList) {
// Not supported in Safari for iOS.
const name = file.name ? file.name : 'NOT SUPPORTED';
// Not supported in Firefox for Android or Opera for Android.
const type = file.type ? file.type : 'NOT SUPPORTED';
// Unknown cross-browser support.
const size = file.size ? file.size : 'NOT SUPPORTED';
console.log({file, name, type, size});
}
}
Veja como isso funciona na demonstração
input-type-file
.
Ler o conteúdo de um arquivo
Use FileReader
para
ler o conteúdo de um objeto File
na memória. Você pode dizer a FileReader
para
ler um arquivo como um buffer de matriz,
um URL de dados
ou texto:
function readImage(file) {
// Check if the file is an image.
if (file.type && !file.type.startsWith('image/')) {
console.log('File is not an image.', file.type, file);
return;
}
const reader = new FileReader();
reader.addEventListener('load', (event) => {
img.src = event.target.result;
});
reader.readAsDataURL(file);
}
Este exemplo lê um File
fornecido pelo usuário, converte-o em um URL de dados e usa esse URL para exibir a imagem em um elemento img
.
Para saber como verificar se o usuário selecionou um arquivo de imagem, consulte a
demonstração do read-image-file
.
Monitorar o progresso da leitura de um arquivo
Ao ler arquivos grandes, pode ser útil fornecer alguma UX para informar ao usuário
até onde a leitura progrediu. Para isso, use o evento
progress
fornecido por FileReader
. O evento progress
tem duas propriedades:
loaded
(a quantidade lida) e total
(a quantidade a ser lida).
function readFile(file) {
const reader = new FileReader();
reader.addEventListener('load', (event) => {
const result = event.target.result;
// Do something with result
});
reader.addEventListener('progress', (event) => {
if (event.loaded && event.total) {
const percent = (event.loaded / event.total) * 100;
console.log(`Progress: ${Math.round(percent)}`);
}
});
reader.readAsDataURL(file);
}
Imagem principal de Vincent Botta do Unsplash.