En este artículo voy a enseñarte a usar el Origin Private File System con JavaScript para almacenar, leer y eliminar cualquier tipo de archivo en el navegador web.
Puedes probar la demostración aquí: https://stackblitz.com/edit/vitejs-vite-hl34zf?file=index.html
Como lo dije anteriormente, el Origin Private File System ha llegado para revolucionar las cosas con JavaScript. Gracias al OPFS podemos tener un sistema de archivos completo con JavaScript directamente en el navegador web.
Con esto, podemos escribir cualquier tipo de archivo en el web browser, así como descargarlo más adelante. Todo ello sin depender de localStorage o cosas similares; es una tecnología diferente.
Se pueden guardar documentos de texto, imágenes, vídeos e incluso bases de datos, además de que no hay necesidad de pedir permiso o confirmación al usuario, todo es transparente.
Para acceder al directorio raíz, invocamos a navigator.storage.getDirectory()
. Este es el directorio raíz, aquí podemos crear más directorios y archivos. Yo crearé uno así:
const directoryName = "pictures";
const opfsRoot = await navigator.storage.getDirectory();
const picturesFolder = await opfsRoot.getDirectoryHandle(directoryName, {
create: true,
});
A partir de aquí, voy a almacenar, leer y eliminar desde picturesFolder
. Toma en cuenta que aquí un “handle” o manejador no es el archivo o directorio en sí, sino su manejador.
Para obtener el archivo invocamos a getFile
y cosas similares, como veremos más adelante.
Ahora que tenemos un manejador de un directorio podemos invocar a getFileHandle
(indicando la opción create
en true
), luego invocar a createWritable
y finalmente invocando a write
.
Lo que se recomienda pasar a la función write es un array búfer o blob, no necesitamos hacer conversiones o cosas similares. Y el archivo puede venir de cualquier lugar; por ejemplo, de un servidor web o de un input tipo file
.
Para este caso voy a usar un input tipo file y la función queda así:
const storeFile = async (file, folder) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = async () => {
const fileName = file.name;
const fileHandle = await folder.getFileHandle(fileName, {
create: true,
});
const writable = await fileHandle.createWritable();
await writable.write(reader.result);
await writable.close();
resolve();
};
reader.onerror = error => {
reject(error);
}
reader.readAsArrayBuffer(file);
});
}
Podemos invocar a esa función desde el change
del input
, un clic de un botón o cualquier otro evento:
$fileSelect.addEventListener("change", async () => {
const files = $fileSelect.files;
for (const file of files) {
await storeFile(file, picturesFolder)
}
$fileSelect.value = "";
renderFiles(picturesFolder);
});
De nuevo, cuando tenemos un manejador o apuntador a un directorio del OPFS podemos recorrerlo con un for await
, extrayendo el nombre del archivo y el manejador. La manera más básica es:
for await (let [name, handle] of folder) {
//
}
En este caso estoy usando JavaScript puro para dibujar los elementos, agregando los listeners para descargar el archivo y eliminarlo.
const renderFiles = async (folder) => {
while ($mainContainer.firstChild) {
$mainContainer.removeChild($mainContainer.firstChild);
}
for await (let [name, handle] of folder) {
const container = Object.assign(document.createElement("div"));
const anchorFileName = Object.assign(document.createElement("a"), {
textContent: name,
href: "javascript:void(0)",
classList: ["file"],
});
const anchorRemove = Object.assign(document.createElement("a"), {
textContent: "Eliminar",
href: "javascript:void(0)",
classList: ["remove"],
});
anchorFileName.addEventListener("click", () => {
downloadFile(name, folder);
});
anchorRemove.addEventListener("click", async () => {
await removeFile(name, folder);
await renderFiles(folder);
})
container.appendChild(anchorFileName);
container.appendChild(anchorRemove);
$mainContainer.append(container);
}
};
Nota: aunque aquí uso la palabra “descargar”, no hay necesidad de servidores o cosas similares. Todo es fuera de línea, lo que hacemos al descargar el archivo es leerlo del navegador y preguntar al usuario la ubicación donde quiere guardarlo.
Ya vimos cómo guardar un archivo en el navegador con JavaScript y también cómo obtener la lista de archivos que existen dentro de un directorio.
Veamos cómo recuperar un archivo. Aquí vamos a descargarlo, pero podemos enviarlo a un servidor o hacer cualquier otra cosa.
const downloadFile = async (fileName, folder) => {
const fileHandle = await folder.getFileHandle(fileName);
const file = await fileHandle.getFile();
const a = document.createElement("a");
const objectUrl = URL.createObjectURL(file);
a.href = objectUrl;
a.download = fileName;
a.click();
URL.revokeObjectURL(objectUrl);
}
El verdadero archivo está en la constante file
, y luego simplemente creamos un enlace para descargarlo con URL.createObjectURL
. Aquí podríamos hacer cualquier otra cosa con el archivo.
Finalmente veamos cómo eliminar un archivo almacenado previamente en el navegador web con JavaScript. Una vez que tenemos su manejador solo invocamos a remove
(toma en cuenta que, al momento de escribir este post, remove
solo funciona en Chrome y Edge):
const removeFile = async (fileName, folder) => {
if (!('remove' in FileSystemFileHandle.prototype)) {
return alert("Tu navegador no soporta la eliminación de archivos");
}
if (!confirm('¿De verdad quieres eliminarlo?')) {
return;
}
const fileHandle = await folder.getFileHandle(fileName);
await fileHandle.remove();
}
El OPFS ha traído consigo dos cosas: el sistema de archivos en sí, y la posibilidad de que varias librerías existentes la usen.
Lo que más me ha gustado es que SQLite3 ahora funciona perfectamente en el navegador web, así que estamos más cerca de crear aplicaciones web sin servidores (para cuando no se necesite ningún servidor) ya que podemos tener una base de datos y también almacenar archivos.
Complementa la información del OPFS con JavaScript mirando el siguiente vídeo: https://www.youtube.com/watch?v=GZ3rvxRdaB4
Te he mostrado las funciones más importantes para usar el Origin Private File System, es un ejemplo muy simple pero que trata de enseñarte lo más importante. Si quieres ver el código completo ve a mi GitHub: https://github.com/parzibyte/hello-opfs-js
Puedes probar el ejemplo en el servidor que tú prefieras, solo asegúrate de enviar los encabezados COOP y COEP. Cuando ejecutes el ejemplo aparecerá la lista de archivos y un campo para que puedas almacenar más ficheros (como en la imagen del inicio del post)
A partir de este ejemplo podemos hacer cosas más complejas, pues ya tenemos todo un sistema de archivos en el navegador web al que podemos acceder con JavaScript.
Incluso podemos encriptar los archivos o mostrarlos como imagen o vídeo; las posibilidades son infinitas.
Espero traer una aplicación más completa en el futuro, mientras tanto te dejo con más posts de JavaScript.
Hoy te voy a presentar un creador de credenciales que acabo de programar y que…
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Esta web usa cookies.