- file:/// permite navegar por el sistema de archivos local desde el navegador en Windows y Android.
- La API de File System Access ofrece lectura y escritura avanzada en archivos y directorios locales.
- La seguridad se basa en permisos explícitos del usuario y en un control claro sobre qué rutas se exponen.
- Existen polyfills y librerías que combinan esta API con métodos clásicos cuando no hay soporte nativo.

Usar el navegador como si fuera un pequeño explorador de archivos es posible y, bien aprovechado, puede ser tremendamente útil. Desde abrir un simple documento local con file:/// hasta trabajar con la potente API de File System Access, hoy en día los navegadores modernos ofrecen muchas más posibilidades de las que solemos usar.
A lo largo de esta guía vamos a ver, paso a paso, cómo abrir archivos locales en el navegador web usando file:/// en Chrome, Edge y Firefox, cómo convertir el propio navegador en un explorador básico en Windows y Android, y cómo los desarrolladores pueden ir un paso más allá gracias a la API de File System Access para leer, escribir y gestionar archivos y carpetas locales desde una aplicación web.
Qué significa realmente abrir archivos locales con file:///
Cuando escribes una ruta que empieza por file:/// en la barra de direcciones del navegador, le estás diciendo al navegador que en lugar de ir a Internet acceda al sistema de archivos local. Es decir, que abra algo que está en tu propio dispositivo: un disco duro, una memoria interna o una tarjeta SD.
Este esquema de URL especial (file:///) funciona de forma parecida a escribir C: en Windows o / en Linux y macOS, solo que adaptado a la lógica del navegador. A partir de ahí, lo que verás es una especie de listado de carpetas y ficheros, sin florituras: nombres, tamaños, fecha de modificación y poco más.
Eso sí, hay que tener en cuenta que los navegadores tratan estas rutas locales con muchas restricciones de seguridad. Por ejemplo, una página web que visitas desde Internet no puede, por defecto, leer libremente tus archivos locales solo porque tú abras una URL con file:///. Siempre se exige un gesto o permiso explícito del usuario.
Usar el navegador como explorador de archivos en Android
En muchos móviles Android el fabricante no incluye un gestor de archivos decente, o el que viene de serie es un poco limitado. En esos casos, tirar de Chrome, Edge u otro navegador basado en Chromium como explorador improvisado puede sacarte del apuro.
El truco es muy sencillo: abre tu navegador basado en Chromium (Chrome, Edge, Brave, etc.) y escribe en la barra de direcciones file:///sdcard/. Android identifica el almacenamiento interno principal como sdcard, de manera muy similar a como Windows usa C: para la unidad principal.
Al lanzar esa dirección, lo habitual es que el navegador te pida permiso para leer el almacenamiento interno. En cuanto concedas ese permiso, aparecerá un índice con las carpetas raíz de tu memoria interna. Desde ahí puedes ir entrando y saliendo de carpetas exactamente igual que si estuvieras navegando por una web de enlaces.
En cada carpeta verás tanto subcarpetas como archivos. Los archivos se muestran con su nombre completo, incluyendo la extensión, su tamaño y la última fecha de modificación. También se listan las carpetas ocultas, que en Android suelen empezar con un punto, como .nomedia u otras similares.
Aunque el listado es muy espartano, la mayoría de navegadores modernos son capaces de abrir directamente muchos tipos de archivos al tocarlos: imágenes, vídeos, audios, documentos de texto, etc. No hay miniaturas ni previsualizaciones, pero basta con pulsar sobre el nombre del archivo para que el navegador intente mostrarlo o reproducirlo.
Convertir Chrome y Edge en un pequeño explorador de archivos en PC
En ordenadores de escritorio, tanto en Windows como en otros sistemas, también puedes usar Chrome, Edge y otros navegadores basados en Chromium para navegar por tus discos locales con file:///. El principio es el mismo que en Android, pero cambiando la ruta.
Si usas Windows, lo más común es que la unidad principal sea C:. En ese caso, escribe en la barra de direcciones file:///C: y pulsa Intro. El navegador te mostrará el contenido de la raíz de esa unidad: carpetas como Windows, Program Files, Usuarios, etc.
Si tienes más unidades o particiones, puedes sustituir la letra en la URL por la que corresponda. Por ejemplo, file:///D: para otro disco o file:///E: para una memoria USB que se haya montado con esa letra. A partir de ahí, clic en las carpetas para ir avanzando y usa el botón de ir atrás del navegador para retroceder.
Del mismo modo que en Android, en cada carpeta verás archivos y subcarpetas con tamaño, fecha de modificación y extensión visibles. No se generan vistas en miniatura ni iconos bonitos, pero resulta suficiente para localizar un archivo concreto o echar un vistazo rápido a la estructura de un directorio.
La mayoría de navegadores Chromium permiten abrir directamente archivos multimedia e incluso algunos formatos de documentos simplemente haciendo clic sobre ellos. Imágenes, vídeos, audios o ficheros de texto plano se muestran con bastante naturalidad dentro de la pestaña.
Abrir archivos locales en Chrome y Firefox sin escribir file:/// a mano
Además de teclear rutas con file:///, los navegadores incluyen atajos pensados justamente para abrir ficheros locales de forma rápida. En Chrome, por ejemplo, puedes usar la combinación de teclas Ctrl + O (Control + O) cuando la ventana del navegador está activa.
Al pulsar ese atajo, se abre el típico cuadro de diálogo de “Abrir archivo” del sistema operativo. Solo tienes que buscar el archivo que te interese, seleccionarlo y confirmar. Chrome lo cargará en la pestaña actual o en una nueva, según el tipo de archivo y las preferencias.
En Firefox tienes varias opciones. Por un lado, puedes ir al menú principal y elegir la opción “Abrir archivo…”, que hace exactamente lo mismo: mostrar la ventana de selección de archivo del sistema. Por otro, puedes escribir directamente en la barra de direcciones una ruta del tipo file:///// para que el navegador empiece mostrando el contenido de la unidad C: en Windows.
Con cualquiera de estos métodos, el resultado práctico es que el navegador se convierte en un visor de archivos locales. Puede ayudarte cuando el Explorador de Windows se cuelga, cuando tienes problemas con el gestor de archivos habitual o simplemente cuando quieres abrir un tipo de documento que el navegador maneja particularmente bien.
La API de File System Access: el salto de visor a editor
Todo lo que hemos visto hasta ahora se basa en el uso “manual” de file:/// y en los cuadros de diálogo de abrir archivo, es decir, en cosas que hace el usuario a mano. Pero desde hace un tiempo, los navegadores basados en Chromium incorporan la API de File System Access, que da a las aplicaciones web la capacidad de trabajar con archivos locales de una forma mucho más avanzada.
Esta API permite que una web, tras pedir tu permiso, lea y guarde cambios directamente en archivos y carpetas de tu dispositivo. Gracias a ello se pueden crear desde el navegador editores de texto serios, IDEs de programación, editores de foto y vídeo, gestores de proyectos y muchas otras herramientas que antes solo tenía sentido desarrollar como aplicaciones de escritorio.
Es importante no confundir esta API moderna con otras más antiguas o ya obsoletas. No es lo mismo que la interfaz FileSystem de la API de File and Directory Entries ni que la antigua especificación “File API: Directories and System”, que proponían otros mecanismos para tratar jerarquías de archivos y zonas de almacenamiento en sandbox.
La API de File System Access actual se ha diseñado con especial cuidado en materia de seguridad, permisos y experiencia de usuario. Siempre requiere acciones explícitas (como hacer clic en un botón) para abrir el selector de archivos o directorios, y el usuario tiene claro en todo momento a qué rutas exactas está dando acceso.
En cuanto a compatibilidad, la API funciona en la mayoría de navegadores basados en Chromium en Windows, macOS, Linux, ChromeOS y Android. Una excepción destacada es Brave, donde todavía es necesario activar una marca (flag) para poder utilizarla. Otros navegadores no Chromium pueden no implementarla o hacerlo de forma parcial.
Comprobar si el navegador soporta la API de File System Access
Como desarrollador, lo primero que te interesa saber es si el navegador del usuario soporta esta API antes de intentar usarla. La forma más sencilla es mirar si existen los métodos de selección de archivos correspondientes en el objeto global, por ejemplo comprobando si showOpenFilePicker está disponible en window (o self en un worker).
El patrón típico consiste en algo parecido a: “si ‘showOpenFilePicker’ está en self, entonces puedo usar la API; si no, debo recurrir a un método alternativo”. Esto permite implementar soluciones híbridas donde, si hay soporte, se aprovechan las ventajas de la API, y si no lo hay se cae a técnicas tradicionales como los formularios de subida de archivos.
También es buena idea testear en los navegadores destino y en distintos sistemas operativos, porque aunque la base sea Chromium, algunos fabricantes pueden activar o desactivar características concretas por motivos de seguridad, política o rendimiento.
Primer ejemplo: abrir un archivo local desde una app web
Uno de los ejemplos canónicos para entender esta API es construir un editor de texto de un solo archivo que permita abrir, modificar y volver a guardar un documento. No hace falta que sea espectacular: con que lea y escriba texto plano ya ilustra bien el funcionamiento.
El punto de entrada aquí es el método window.showOpenFilePicker(). Este método, que solo puede llamarse en un contexto seguro (HTTPS) y en respuesta a un gesto de usuario, muestra un diálogo nativo para que el usuario elija un archivo. Una vez seleccionado, devuelve un array de manejadores, normalmente con un único FileSystemFileHandle.
Ese manejador almacena toda la información y métodos necesarios para trabajar con el fichero elegido. Conviene guardar una referencia al handle, porque será el que uses más tarde para leer el archivo, guardar cambios o realizar cualquier otra operación. Mientras mantengas ese handle y el usuario no haya revocado permisos, tu app podrá interactuar con el archivo.
Una vez que tienes el FileSystemFileHandle, puedes obtener el objeto File real llamando a handle.getFile(). Este objeto File contiene los datos del archivo como un blob, y puedes acceder a su contenido con métodos como text(), arrayBuffer(), stream() o slice() si necesitas acceso aleatorio.
En la práctica, para un editor de texto sencillo, lo habitual es usar file.text() para obtener el contenido completo como cadena, y volcar ese texto en un <textarea> para que el usuario lo edite. Hay que tener en cuenta que el objeto File deja de ser válido si el archivo se modifica en disco por otra vía, en cuyo caso conviene volver a llamar a getFile().
Guardar cambios: escribir en el sistema de archivos local
Para guardar lo que el usuario ha editado, la API ofrece dos caminos típicos: un guardado “simple” que sobrescribe el archivo original y un “Guardar como” que crea un archivo nuevo. La diferencia fundamental es si ya tienes un handle al archivo destino o si necesitas que el usuario elija una nueva ruta y nombre.
Cuando quieres crear un archivo nuevo o guardar una copia con otro nombre, debes usar showSaveFilePicker(). Este método abre el selector de archivos en modo guardado, permitiendo que el usuario indique nombre, carpeta y extensión. Puedes pasarle opciones para sugerir tipos de archivo, por ejemplo indicar que se trata de documentos de texto y que la extensión preferida sea .txt.
Un detalle importante es que debes llamar a showSaveFilePicker() directamente en respuesta al gesto del usuario (por ejemplo, el clic en el botón “Guardar”) y no retrasarlo mientras haces procesado pesado. Si haces todo el trabajo previo y luego, con retraso, intentas abrir el diálogo, el navegador puede lanzar un error de seguridad porque ya no se considera que estás “manejando un gesto de usuario”.
Una vez tienes un FileSystemFileHandle apuntando al archivo donde quieres guardar, el siguiente paso es crear un FileSystemWritableFileStream usando fileHandle.createWritable(). Este stream es el que utilizarás para escribir los datos. Si el navegador detecta que aún no tienes permiso de escritura, te mostrará un cuadro de permisos; si el usuario lo deniega, la llamada lanza una excepción.
Con el stream en la mano, simplemente llamas a writable.write(contenido) con una cadena, un Blob o un BufferSource. Puedes incluso canalizar directamente el cuerpo de una respuesta HTTP hacia el stream con response.body.pipeTo(writable). Cuando terminas de escribir, cierras la transmisión con writable.close(), que es el momento en que los cambios se consolidan en disco.
Mientras la transmisión está abierta, también puedes utilizar métodos como seek() o truncate() para mover el puntero de escritura a una posición concreta o cambiar el tamaño del archivo. Pero hay que recordar que los cambios no se aplican de forma definitiva hasta que se cierra el stream.
Sugerir nombre de archivo y carpeta de inicio al usuario
La API también cuida la experiencia de usuario en los cuadros de diálogo del sistema. Por ejemplo, puedes indicar un nombre de archivo sugerido cuando llamas a showSaveFilePicker(). Eso permite que, en lugar de mostrar un genérico “Sin título”, el usuario vea algo más descriptivo como “Documento nuevo.txt”.
Del mismo modo, es posible sugerir una carpeta inicial en la que empiece el selector de archivos. Esto se hace pasando una propiedad startIn cuando llamas a showSaveFilePicker(), showOpenFilePicker() o showDirectoryPicker(). Los valores pueden ser cadenas como desktop, documents, downloads, music, pictures o videos, que corresponden a ubicaciones estándar del sistema.
Además, tienes la opción de usar como valor de startIn un manejador de archivo o de directorio que ya tengas. En ese caso, el cuadro de diálogo se abre directamente en la carpeta donde resida ese handle, lo que es muy cómodo para retomar el contexto de trabajo de la última sesión.
Si tu aplicación maneja distintos tipos de archivos (por ejemplo, documentos de texto e imágenes incrustadas), puedes definir IDs distintos para cada tipo de cuadro de diálogo. De este modo, el navegador recordará la última carpeta usada de forma independiente para cada ID, y no mezclarás las rutas de documentos con las de imágenes.
Recordar archivos y carpetas recientes con IndexedDB
Uno de los puntos fuertes de File System Access es que sus manejadores son serializables. Esto significa que puedes almacenar FileSystemFileHandle y FileSystemDirectoryHandle en IndexedDB y recuperarlos en sesiones posteriores, siempre respetando la política de permisos.
Gracias a esto, las aplicaciones web pueden ofrecer funcionalidades típicas de escritorio como listas de archivos recientes, reapertura del último proyecto o recuperación de la carpeta de trabajo anterior. Solo hay que guardar los handles en la base de datos del navegador y leerlos al iniciar la app.
Cuando recuperes un handle almacenado, no des por hecho que los permisos se mantienen. El navegador puede decidir que hay que volver a pedir autorización, por ejemplo porque ha pasado tiempo o se ha cerrado la última pestaña de ese origen. Por eso es recomendable que tu código compruebe la situación.
Para esta comprobación, la API incluye los métodos queryPermission() y requestPermission() tanto en manejadores de archivo como de directorio. Primero preguntas en qué estado está el permiso, y si no es “granted”, puedes solicitarlo de nuevo al usuario, indicando en las opciones si necesitas solo lectura o lectura y escritura.
Una buena práctica es combinar ambos pasos en una función de ayuda que, dado un handle y un modo (solo lectura o lectura/escritura), verifique si ya hay permiso y, de no haberlo, muestre el prompt correspondiente. Así reduces el número de diálogos y haces la experiencia más fluida.
Abrir y recorrer directorios completos desde el navegador
Además de archivos sueltos, la API permite trabajar con carpetas enteras. Con showDirectoryPicker() el usuario puede seleccionar un directorio completo, y la aplicación recibe un FileSystemDirectoryHandle que da acceso a todos sus elementos.
Por defecto tendrás permiso de lectura sobre los archivos de ese directorio, aunque si necesitas escribir también en ellos puedes solicitar acceso de lectura y escritura pasando { mode: 'readwrite' } al llamar a showDirectoryPicker(). Desde ese momento, tu app puede listar y manipular el contenido según el permiso concedido.
Para recorrer la carpeta, puedes iterar de forma asíncrona sobre dirHandle.values(), que va devolviendo uno a uno los elementos que contiene: archivos y subdirectorios. Cada entrada tiene una propiedad kind que te indica si se trata de un "file" o un "directory".
Si necesitas acceder a información de cada archivo, como su tamaño, puedes llamar a entry.getFile(). Lo recomendable en estos casos es lanzar las lecturas en paralelo usando Promise.all() o técnicas similares, en lugar de ir una por una de manera estrictamente secuencial, que puede resultar más lenta.
Desde un directorio también puedes crear nuevas carpetas o archivos con getDirectoryHandle() y getFileHandle(), indicando en las opciones si quieres que se creen si no existen. Por ejemplo, puedes montar una estructura de proyecto tipo “Mi proyecto / Código / Notas.txt” directamente desde la aplicación web.
Gestionar archivos: borrar, renombrar y mover
La API no se limita a leer y escribir. También te permite eliminar archivos y carpetas de un directorio usando removeEntry() sobre un FileSystemDirectoryHandle. Si se trata de una carpeta, puedes hacer que el borrado sea recursivo, de forma que incluya todas sus subcarpetas y archivos.
Si en lugar de pasar por el directorio quieres actuar directamente sobre un manejador de archivo o de carpeta, algunos navegadores ofrecen el método remove() en FileSystemFileHandle y FileSystemDirectoryHandle. De este modo eliminas ese elemento sin necesidad de referirte a su nombre dentro del directorio padre.
Para operaciones de organización como cambiar nombres o mover elementos a otra carpeta, existe el método move() en la interfaz FileSystemHandle. Puedes pasarle directamente un nuevo nombre, un directorio de destino, o un directorio más el nuevo nombre para hacer movimiento y renombrado a la vez.
Eso sí, hay matices de compatibilidad: el soporte de move() está más maduro para archivos dentro del sistema de archivos privado de origen (OPFS), y aún puede estar detrás de flags o no estar implementado para todos los escenarios ni para directorios en ciertos navegadores.
Arrastrar y soltar archivos y carpetas hacia la web
La API de File System Access se integra muy bien con el sistema de arrastrar y soltar de HTML. Cuando el usuario arrastra archivos o carpetas desde el sistema operativo a una página web, el navegador crea elementos DataTransferItem asociados.
A través del método DataTransferItem.getAsFileSystemHandle(), puedes obtener un FileSystemFileHandle si el elemento es un archivo o un FileSystemDirectoryHandle si es un directorio. Así, una app puede aceptar que el usuario arrastre una carpeta completa de fotos y trabajar directamente sobre su contenido.
Debes tener en cuenta que, en el contexto de arrastrar y soltar, DataTransferItem.kind será siempre «file» tanto para archivos como para carpetas. La distinción entre archivo y directorio la obtendrás consultando la propiedad kind del FileSystemHandle que te devuelva getAsFileSystemHandle(), que sí diferenciará entre "file" y "directory".
Sistema de archivos privado de origen (OPFS) y acceso optimizado
Además del acceso a archivos y carpetas del usuario, los navegadores Chromium ofrecen un sistema de archivos privado de origen (origin private file system u OPFS). Se trata de un espacio de almacenamiento dedicado a cada sitio web, no directamente accesible por el usuario desde el sistema operativo.
En la práctica, esto significa que aunque internamente el navegador almacene estos datos en disco, el usuario no va a encontrarlos como archivos “normales” en una carpeta cualquiera. Puede tratarse de una base de datos, archivos empaquetados o cualquier estructura interna que el navegador considere conveniente.
Desde la API puedes acceder a la raíz de este sistema privado mediante navigator.storage.getDirectory(), que devuelve un FileSystemDirectoryHandle. A partir de ahí puedes crear archivos y directorios, leerlos, escribirlos, renombrarlos o borrarlos igual que si fueran elementos del sistema de archivos local, pero sabiendo que están aislados y dedicados exclusivamente a tu aplicación web.
Para necesidades de rendimiento más avanzado, Chromium incorpora un tipo especial de archivo con acceso síncrono optimizado. A través de fileHandle.createSyncAccessHandle() (disponible en workers), puedes obtener un handle que permite leer y escribir de forma síncrona y en modo exclusivo, algo útil para casos de uso muy intensivos o sensibles a la latencia.
La obtención del handle sigue siendo asíncrona, pero una vez lo tienes, las operaciones de lectura y escritura se realizan como llamadas directas, manipulando buffers de bytes. Esto se acerca mucho al rendimiento de una aplicación nativa, pero sin abandonar el entorno web y manteniendo el aislamiento del sistema privado de origen.
Polyfills y alternativas cuando no hay soporte nativo
Aunque la API de File System Access ofrece muchas posibilidades, no todos los navegadores la soportan todavía. No se puede hacer un polyfill completo que reproduzca todas sus capacidades, principalmente porque no hay forma de simular de forma fiable el acceso nativo al sistema de archivos sin la cooperación del propio navegador.
Sin embargo, se pueden aproximar algunas partes. Para emular showOpenFilePicker() suele recurrirse a un simple <input type="file">, que muestra el cuadro de selección de archivos y permite al usuario elegir uno o varios ficheros.
Algo similar ocurre con el guardado. Para imitar showSaveFilePicker() se usa muchas veces un enlace <a download="nombre"> que, al pulsarlo, inicia la descarga de un Blob generado desde JavaScript. Esto permite “guardar” datos generados por la web, aunque no ofrece la opción de sobrescribir archivos ya existentes.
En cuanto a seleccionar directorios completos, se ha usado tradicionalmente el atributo no estándar webkitdirectory en <input type="file">, que permite elegir una carpeta y recibir la lista de ficheros que contiene. No es una solución universal ni tan potente como showDirectoryPicker(), pero cubre algunos casos.
Para unificar estas aproximaciones, existen librerías como browser-fs-access que intentan usar la API moderna siempre que está disponible y, si no, recurren automáticamente a estas mejores alternativas. De este modo el desarrollador escribe un código relativamente uniforme y la biblioteca se encarga de adaptarse al entorno.
Seguridad, permisos y control del usuario
Toda esta potencia conlleva responsabilidades, y los equipos de navegador son muy conscientes de ello. El diseño de la API de File System Access gira en torno a dos principios: control del usuario y transparencia. Nada de que una web pueda leer medio disco duro a escondidas.
Cuando el usuario abre un archivo mediante los cuadros de selección (ya sea para leer o para guardar uno nuevo), es ese gesto el que otorga el permiso de lectura o escritura sobre el archivo o carpeta concreta. Si el usuario cambia de idea y cancela el diálogo, la web no recibe nada y, por tanto, no obtiene ningún tipo de acceso.
Para guardar un archivo nuevo, el cuadro de “Guardar” no solo permite elegir nombre y ruta, sino que también sirve de concesión de permiso de escritura sobre ese archivo recién creado. La lógica es la misma que se ha utilizado durante años en elementos como <input type="file">, pero extendida con más capacidades.
Cuando una aplicación web quiere modificar un archivo que ya existía, no puede hacerlo sin más; el navegador puede mostrar un aviso específico pidiendo permiso para escribir en él. Este diálogo solo puede abrirse en respuesta a una acción del usuario, como pulsar un botón “Guardar cambios”.
Si el usuario decide no conceder ese permiso de escritura, la web debe ofrecer alguna alternativa: descargar una copia, guardar en la nube, trabajar en el OPFS u otro mecanismo similar. La idea es que el usuario tenga siempre la última palabra sobre qué se toca en su sistema local.
A nivel de transparencia, los navegadores muestran un icono en la barra de direcciones cuando una web tiene acceso a archivos locales. Si el usuario hace clic en ese icono, verá una lista de los archivos o carpetas a los que la página tiene acceso en ese momento y podrá revocar permisos cuando quiera.
Los permisos no son eternos. Generalmente, una página conserva la capacidad de seguir guardando archivos solo mientras haya al menos una pestaña de ese origen abierta. Una vez se cierran todas, el navegador puede considerar que se termina la sesión y, en el siguiente uso, será necesario volver a pedir permiso para esos archivos o directorios.
Combinar el esquema file:/// para abrir recursos puntuales, los atajos de teclado para cargar archivos locales y la API de File System Access para integraciones profundas convierte al navegador en una herramienta mucho más versátil tanto para usuarios como para desarrolladores, permitiendo desde visualizar rápidamente un vídeo guardado en el disco hasta editar proyectos completos sin salir del entorno web.
Redactor apasionado del mundo de los bytes y la tecnología en general. Me encanta compartir mis conocimientos a través de la escritura, y eso es lo que haré en este blog, mostrarte todo lo más interesante sobre gadgets, software, hardware, tendencias tecnológicas, y más. Mi objetivo es ayudarte a navegar por el mundo digital de forma sencilla y entretenida.