Ler arquivos em JavaScript

Selecionar arquivos e interagir com eles no dispositivo local do usuário é um dos recursos mais usados com frequência da Web. Ele permite que os usuários selecionem arquivos e façam upload deles para um servidor, por exemplo, ao compartilhar fotos ou enviar documentos fiscais. Ele também permite que os sites leiam e manipulem arquivos sem precisar transferir os dados pela rede. Esta página explica como usar o JavaScript para interagir com arquivos.

A API File System Access moderna

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, consulte A API File System Access.

Como a API File System Access não é compatível com todos os navegadores, nós recomendamos o uso de browser-fs-access, uma biblioteca auxiliar que usa a nova API sempre que ela está disponível e volta a abordagens legadas quando não está.

Trabalhar com arquivos, da maneira clássica

Este guia mostra 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 para os usuários selecionarem arquivos é usando o <input type="file"> elemento, que é compatível com todos os principais navegadores. Quando clicado, ele permite que um usuário selecione um ou vários arquivos, se o multiple atributo estiver incluído, usando a interface de seleção de arquivos integrada do sistema operacional. Quando o usuário termina de selecionar um ou mais arquivos, o evento change do elemento é acionado. É possível acessar a lista de arquivos de event.target.files, que é um FileList objeto. Cada item no 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 interface 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 arquivos que os usuários podem selecionar. Por exemplo, um app de edição de imagens só deve aceitar imagens, não arquivos de texto. Para definir restrições de tipo de arquivo, adicione um accept atributo ao elemento de entrada para especificar quais tipos de arquivo são aceitos:

<input type="file" id="file-selector" accept=".jpg, .jpeg, .png">

Arrastar e soltar personalizado

Em alguns navegadores, o <input type="file"> elemento também é um destino de soltura, permitindo que os usuários arrastem e soltem arquivos no seu app. No entanto, esse destino de soltura é pequeno e pode ser difícil de usar. Em vez disso, depois de fornecer recursos principais usando um <input type="file"> elemento, você pode fornecer uma superfície grande e personalizada de arrastar e soltar.

Escolher sua zona de soltura

A superfície de soltura depende do design do aplicativo. Talvez você só queira que parte da janela seja uma superfície de soltura, mas é possível usar a janela inteira.

Captura de tela do Squoosh, um app da Web de compactação de imagens.
O Squoosh transforma a janela inteira em uma zona de soltura.

O app de compactação de imagens Squoosh permite que o usuário arraste uma imagem para qualquer lugar da janela e clique em Selecionar uma imagem para invocar o <input type="file"> elemento. Seja qual for a zona de soltura escolhida, deixe claro para o usuário que ele pode arrastar arquivos para essa superfície.

Definir a zona de soltura

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 é acionado depois que o usuário solta os arquivos na superfície. Assim como no elemento de entrada, é possível acessar a lista de arquivos de event.dataTransfer.files, que é um FileList objeto. Cada item no 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 que o código seja executado. Sem eles, o navegador sairia da página e abriria os arquivos que o usuário soltou na janela do navegador.

Para uma demonstração ao vivo, consulte Arrastar e soltar personalizado.

E os diretórios?

Infelizmente, não há uma boa maneira de acessar um diretório usando JavaScript.

O webkitdirectory atributo no elemento <input type="file"> permite que o usuário escolha um ou mais diretórios. Ele é compatível com a maioria dos principais navegadores exceto o Firefox para Android e o Safari no iOS.

Se o recurso de arrastar e soltar estiver ativado, um usuário poderá tentar arrastar um diretório para a zona de soltura. Quando o evento de soltura é acionado, ele inclui um objeto File para o diretório, mas não fornece acesso a nenhum dos arquivos no diretório.

Ler metadados de arquivos

O File objeto contém metadados sobre o arquivo. A maioria dos navegadores fornece o nome do arquivo, o tamanho e o tipo MIME, embora, dependendo da plataforma, navegadores diferentes possam 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});
  }
}

É possível conferir isso na input-type-file demonstração.

Ler o conteúdo de um arquivo

Use FileReader para ler o conteúdo de um objeto File na memória. É possível instruir FileReader a 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 read-image-file demonstração.

Monitorar o progresso de uma leitura de arquivo

Ao ler arquivos grandes, pode ser útil fornecer alguma experiência do usuário para informar ao usuário o progresso da leitura. Para isso, use o progress evento 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);
}