Lendo arquivos com FileReader - JavaScript
No JavaScript, o objeto FileReader
Métodos do FileReader
Os métodos do FileReader permitem diferentes maneiras de acessar os dados do arquivo:
: Lê o arquivo como uma string de bytes.readAsBinaryString()
: Lê o conteúdo do arquivo como texto.readAsText()
: 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 comreadAsDataURL()
, seguidas pelo tipo MIME e pelos dados codificados (por exemplo,data:
). Isso é útil para reduzir solicitações HTTP, já que os dados, como imagens, podem ser usados diretamente no HTML.data:image/png;base64,...
: Lê os dados como umreadAsArrayBuffer()
, ideal para manipulações binárias avançadas.ArrayBuffer
: Interrompe o processo de leitura.abort()
Eventos Associados ao FileReader
: Disparado quando a leitura é interrompida comabort
.abort()
: Disparado quando ocorre um erro durante a leitura.error
: Disparado quando a leitura é concluída com sucesso.load
: Disparado no início do processo de leitura.loadstart
: Disparado ao final da leitura, seja bem-sucedida ou interrompida.loadend
: Disparado durante a leitura, indicando progresso.progress
Ao concluir a leitura, o evento load
result
FileReader
event.target.result
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
accept="text/*"
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
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
Trabalhando com Imagens
O FileReader
<!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
<input type="file" id="files" accept="image/*" multiple />
A leitura do arquivo é feita usando o método readAsDataURL()
src
<img />
Cada imagem é exibida em um contêiner <div>
<h3>
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>
text
<img>
O método match()
text.*
image.*