Lendo arquivos com FileReader - JavaScript

No JavaScript, o objeto FileReader é utilizado para ler arquivos selecionados pelo usuário em uma aplicação web. Ele oferece diversas formas de leitura, permitindo que os dados sejam manipulados de acordo com as necessidades do desenvolvedor.

Métodos do FileReader

Os métodos do FileReader permitem diferentes maneiras de acessar os dados do arquivo:

  • readAsBinaryString(): Lê o arquivo como uma string de bytes.

  • readAsText(): Lê o conteúdo do arquivo como texto.

  • readAsDataURL(): Lê o arquivo como uma URL de dados. URLs de dados são strings que incorporam dados diretamente no código HTML. Elas começam com data:, seguidas pelo tipo MIME e pelos dados codificados (por exemplo, data:image/png;base64,...). Isso é útil para reduzir solicitações HTTP, já que os dados, como imagens, podem ser usados diretamente no HTML.

  • readAsArrayBuffer(): Lê os dados como um ArrayBuffer, ideal para manipulações binárias avançadas.

  • abort(): Interrompe o processo de leitura.

Eventos Associados ao FileReader

  • abort: Disparado quando a leitura é interrompida com abort().

  • error: Disparado quando ocorre um erro durante a leitura.

  • load: Disparado quando a leitura é concluída com sucesso.

  • loadstart: Disparado no início do processo de leitura.

  • loadend: Disparado ao final da leitura, seja bem-sucedida ou interrompida.

  • progress: Disparado durante a leitura, indicando progresso.

Ao concluir a leitura, o evento load é disparado. Os dados lidos podem ser acessados pela propriedade result do FileReader ou por meio de event.target.result no manipulador de eventos.

Abaixo, temos um exemplo de como usar o FileReader para ler arquivos de texto selecionados pelo usuário com um elemento <input type="file" />.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Lendo Arquivos com FileReader</title>
</head>
<body>
    <input type="file" id="files" accept="text/*" multiple />
    <script>
        function printFiles(e) {
            const files = e.target.files; // Obtém os arquivos selecionados
            
            for (const file of files) { // Itera sobre os arquivos
                const reader = new FileReader(); // Cria um FileReader para cada arquivo
                
                reader.onload = () => {
                    console.log(reader.result); // Exibe o conteúdo no console
                    console.log("=============================="); // Separador para múltiplos arquivos
                };

                reader.readAsText(file); // Lê o arquivo como texto
            }
        }

        document.getElementById("files").addEventListener("change", printFiles);
    </script>
</body>
</html>

Neste exemplo, o elemento input é utilizado como um campo de entrada para seleção de arquivos, permitindo apenas arquivos de texto (accept="text/*") e múltiplos arquivos (multiple):

<input type="file" id="files" accept="text/*" multiple />

Quando o usuário seleciona arquivos, o evento change é disparado, chamando a função printFiles:

document.getElementById("files").addEventListener("change", printFiles);

Os arquivos são acessados por meio da propriedade e.target.files. Cada arquivo é processado individualmente:

const files = e.target.files;
for (const file of files) {
    const reader = new FileReader();
    reader.onload = () => console.log(reader.result);
    reader.readAsText(file);
}

Após a leitura, os dados do arquivo são exibidos no console. Um separador é adicionado para distinguir o conteúdo de múltiplos arquivos:

reader.onload = () => {
    console.log(reader.result);
    console.log("==============================");
};

Após selecionar um ou mais arquivos de texto, o conteúdo de cada um será exibido no console, seguido de um separador:

Conteúdo do arquivo 1...
==============================
Conteúdo do arquivo 2...
==============================

Exibindo Metadados do Arquivo

Além do conteúdo do arquivo, o FileReader também permite trabalhar com metadados adicionais, como o nome do arquivo. Esses metadados estão disponíveis por meio das propriedades do objeto File.

Uma abordagem inicial para exibir o nome do arquivo junto com seu conteúdo seria algo assim:

for (file of files) {
    console.log("File Name:", file.name); // Exibindo o nome do arquivo
    const reader = new FileReader();
    reader.onload = () => {
        console.log("File Name:", file.name); // Tentativa de exibir o nome novamente
        console.log(reader.result);
        console.log("==============================");
    };
    reader.readAsText(file);
}

No entanto, o código acima contém um problema: como o método reader.onload é assíncrono, pode ocorrer um atraso na leitura do arquivo. Isso pode resultar em conflitos, como o nome de um arquivo sendo exibido junto com o conteúdo de outro.

Para evitar esses conflitos, usamos um closure para capturar os dados necessários antes da execução do código assíncrono:

function printFiles(e) {  
    const files = e.target.files;
    for (file of files) {
        const reader = new FileReader();
        reader.onload = (function(fileData) {
            return function(e) {
                console.log("File Name:", fileData.name); // Nome correto garantido
                console.log(e.target.result);
                console.log("==============================");
            };
        })(file);
        reader.readAsText(file);       
    }
}

Isso funciona porque a função autoexecutada (IIFE) cria um escopo único para cada iteração, preservando o estado atual do arquivo dentro da variável fileData. Isso elimina o problema de sobrescrita no contexto assíncrono.

Trabalhando com Imagens

O FileReader também pode ser usado para exibir imagens diretamente no navegador. Aqui está um exemplo onde arquivos de imagem são carregados e exibidos na página:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Exibindo Imagens</title>
    <style>
        div.fileItem { margin: 10px; text-align: center; }
        img.image { width: 250px; }
    </style>
</head>
<body>
    <input type="file" id="files" accept="image/*" multiple />
    <div id="fileList"></div>
    <script>
        function printFiles(e) {  
            const files = e.target.files;
            for (file of files) {
                const reader = new FileReader();
                reader.onload = (function(fileData) {
                    return function() {
                        const fileItem = document.createElement("div");
                        fileItem.className = "fileItem";

                        const fileHeader = document.createElement("h3");
                        fileHeader.textContent = fileData.name;
                        fileItem.appendChild(fileHeader);

                        const img = document.createElement("img");
                        img.src = reader.result;
                        img.className = "image";
                        fileItem.appendChild(img);

                        document.getElementById("fileList").appendChild(fileItem);
                    };
                })(file);
                reader.readAsDataURL(file);
            }
        }
        document.getElementById("files").addEventListener("change", printFiles);
    </script>
</body>
</html>

Neste exemplo, o elemento input é usado para selecionar arquivos de imagem, permitindo múltiplos arquivos:

<input type="file" id="files" accept="image/*" multiple />

A leitura do arquivo é feita usando o método readAsDataURL(), que converte a imagem em uma URL de dados. Essa URL pode ser diretamente atribuída ao atributo src de um elemento <img />, permitindo que a imagem seja exibida na página.

Cada imagem é exibida em um contêiner <div> com o nome do arquivo exibido em um cabeçalho <h3>.

Exemplo de exibição de imagens com FileReader.png

Trabalhando com Diferentes Tipos de Arquivos

Podemos combinar o tratamento de texto e imagens em uma única lógica. Neste exemplo, diferenciamos os tipos de arquivo e exibimos cada um de forma apropriada:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Manipulando Diferentes Tipos de Arquivos</title>
    <style>
        div.fileItem { margin: 10px; text-align: center; }
        div.text { padding: 10px; border: 1px solid #ccc; white-space: pre-wrap; }
        img.image { width: 250px; }
    </style>
</head>
<body>
    <input type="file" id="files" multiple />
    <div id="fileList"></div>
    <script>
        const fileList = document.getElementById("fileList");

        function createFileItem(file) {
            const fileItem = document.createElement("div");
            fileItem.className = "fileItem";
            const fileHeader = document.createElement("h3");
            fileHeader.textContent = file.name;
            fileItem.appendChild(fileHeader);
            return fileItem;
        }

        function handleTextFile(file) {
            return function(e) {
                const fileItem = createFileItem(file);
                const textDiv = document.createElement("div");
                textDiv.textContent = e.target.result;
                textDiv.className = "text";
                fileItem.appendChild(textDiv);
                fileList.appendChild(fileItem);
            };
        }

        function handleImageFile(file) {
            return function(e) {
                const fileItem = createFileItem(file);
                const img = document.createElement("img");
                img.src = e.target.result;
                img.className = "image";
                fileItem.appendChild(img);
                fileList.appendChild(fileItem);
            };
        }

        function printFiles(e) {
            const files = e.target.files;
            for (file of files) {
                const reader = new FileReader();
                if (file.type.match("text.*")) {
                    reader.onload = handleTextFile(file);
                    reader.readAsText(file);
                } else if (file.type.match("image.*")) {
                    reader.onload = handleImageFile(file);
                    reader.readAsDataURL(file);
                }
            }
        }

        document.getElementById("files").addEventListener("change", printFiles);
    </script>
</body>
</html>

Neste exemplo, os arquivos são processados de acordo com seu tipo. Se o arquivo for de texto, ele será exibido em um contêiner <div> com a classe text. Se for uma imagem, ela será exibida em um elemento <img>.

O método match() é usado para verificar o tipo do arquivo. Se o tipo corresponder a text.*, o arquivo será tratado como texto. Se corresponder a image.*, ele será tratado como imagem.

Exemplo de exibição de imagens com FileReader.png
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com