The browsers han podido tratar con archivos y directorios por mucho tiempo. los File API
proporciona funciones para representar objetos de archivo en aplicaciones Web, así como para seleccionarlos a través de programming y ingresar a sus datos. A pesar de todo, en el momento en que miras más de cerca, todo lo que brilla no es oro.
The traditional way of handling files
Open files
As a developer, you can open and read files through the
element. In its simplest form, opening a file may resemble the following code example. the input
the object gives you a FileList
, which in the following case consists of only one
File
. A File
is a specific type of Blob
, and can be used in any context that a Blob can.
const openFile = async () => {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
input.addEventListener('change', () => {
resolve(input.files[0]);
});
input.click();
});
};
Open directories
To open folders (or directories), you can configure the
attribute. Aparte de eso, todo lo demás funciona igual que arriba. Pese a su nombre con prefijo de proveedor,
webkitdirectory
It can be used not only in Chromium and WebKit browsers, but also in legacy EdgeHTML-based Edge and Firefox.
Save (rather: download) files
To store a file, traditionally, you are limited to downloading a file, which works thanks to the
<a download>
attribute. Given a Blob, you can determine the anchor href
attribute to a blob:
Url que puede conseguir del
URL.createObjectURL ()
method.
Caution:
To avoid memory leaks, always revoke the URL after downloading.
const saveFile = async (blob) => {
const to = document.createElement('a');
to.download = 'my-file.txt';
to.href = Url.createObjectURL(blob);
to.addEventListener('click', (and) => {
setTimeout(() => Url.revokeObjectURL(to.href), 30 * 1000);
});
to.click();
};
The problem
A massive downside to to download approach is that there is no way to make a classic open → edit → save flow happen, in other words, there is no way to Overwrite the original file. Instead, you end up with a new Copy from the original file in the default download folder of the operating system every time you "save".
The API del sistema de archivos nativo
The native file system API makes both open and save operations much easier. Furthermore, it enables real savingsIn other words, you can not only choose where to save a file, but also overwrite an existing file.
Open files
With the Native file system API, opening a file is a matter of a call to the window.showOpenFilePicker ()
method. This call returns a file handle, from which you can get the File
through him getFile ()
method.
const openFile = async () => {
try {
const [handle] = await window. showOpenFilePicker();
return handle.getFile();
} catch (err) {
console.error(err.yam, err.message);
}
};
Open directories
Open a directory by calling
window.showDirectoryPicker ()
which makes directories selectable in the file dialog.
Save files
Saving files is equally simple. From a file handle, create a write stream using createWritable ()
, then write the Blob data by calling the flow write ()
method, and in conclusion closes the sequence by calling its close ()
method.
const saveFile = async (blob) => {
try {
const handle = await window.showSaveFilePicker({
types: [{
accept: {
},
}],
});
const writable = await handle.createWritable();
await writable.write(blob);
await writable.close();
return handle;
} catch (err) {
console.error(err.yam, err.message);
}
};
Introducing browser-nativefs
As stupendously good as the native file system API, it is not yet widely available.

Tabla de compatibilidad del browser para la API del sistema de archivos nativo. (Source)
Es es por esto que que veo la API del sistema de archivos nativo como una progressive improvement. Como tal, quiero usarlo cuando el navegador lo admita, y utilizar el enfoque tradicional si no; todo ello sin castigar nunca al Username con descargas innecesarias de código JavaScript no compatible. los browser-nativefs
Library is my answer to this challenge.
Design philosophy
Since the native filesystem API is likely to change in the future, the browser-nativefs API is not based on it. In other words, the library is not a polyfill, but rather a ponyfill. You can (statically or dynamically) exclusively import whatever functionality you need to keep your application as small as possible. The available methods are those appropriately named
fileOpen ()
,
directoryOpen ()
and
fileSave ()
. Internally, the library function detects whether the native file system API is supported and then imports the respective code path.
Using the browser-nativefs library
All three methods are intuitive to use. You can specify acceptance of your application mimeTypes
or file extensions
and establish a multiple
Check to allow or disallow selection of multiple files or directories. For complete details, see the
browser-nativefs API documentation. The following code example shows how you can open and save image files.
import {
fileOpen,
directoryOpen,
fileSave,
} desde 'https://unpkg.com/browser-nativefs';(async () => {
const blob = await fileOpen({
mimeTypes: ['image/*'],
});
const blobs = await fileOpen({
mimeTypes: ['image/*'],
multiple: true,
});
const blobsInDirectory = await directoryOpen({
recursive: true
});
await fileSave(blob, {
fileName: 'Untitled.png',
});
})();
Manifestation
You can see the above code in action in a manifestation in Glitch. Their source code además se encuentra disponible allí. Ya que, por razones de seguridad, los subtramas de origen cruzado no pueden mostrar un selector de archivos, la demostración no se puede incrustar en este post.
The browser-nativefs library in nature
In my spare time, I contribute a little bit to an installable PWA called Excalidraw, una herramienta de pizarra que le posibilita esbozar diagramas fácilmente con una sensación de dibujado a mano. Es completamente sensible y va bastante bien en una gama de dispositivos, desde pequeños teléfonos móviles hasta computadoras con pantallas grandes. Esto significa que debe manejar archivos en todas las diversas plataformas, ya be que admitan o no la API del sistema de archivos nativo. Esto lo convierte en un gran candidato para la biblioteca browser-nativefs.
I can, as an example, start a drawing on my iPhone, save it (technically: download it, since Safari doesn't support the native file system API) to the Downloads folder on my iPhone, open the file on my desktop ( after transferring it from my phone), modify the file and overwrite it with my changes, or even save it as a new file.

Launch an Excalidraw drawing on an iPhone where the native file system API is not supported, but where a file can be saved (downloaded) in the Downloads folder).

Open and modify the Excalidraw drawing on the desktop where the native file system API is supported, so the file can be accessed using the API.

Overwriting the original file with modifications to the original Excalidraw drawing file. The browser shows a dialog asking me if it's okay.

Save the modifications in a new Excalidraw file. The original file remains intact.
Real life code example
Below you can see a real example of browser-nativefs as used in Excalidraw. This extract is taken from
/src/data/json.ts
. Of special interest is how saveAsJSON ()
pass a file handle or null
to browser-nativefs'
fileSave ()
, which causes it to be overwritten when a handle is assigned, or to be saved to a new file if not.
export const saveAsJSON = async (
elements: readonly ExcalidrawElement[],
appState: AppState,
fileHandle: any,
) => {
const serialized = serializeAsJSON(elements, appState);
const blob = new Blob([serialized], {
type: "application/json",
});
const yam = `${appState.yam}.excalidraw`;
(window ace any).handle = await fileSave(
blob,
{
fileName: yam,
description: "Excalidraw file",
extensions: ["excalidraw"],
},
fileHandle || null,
);
};export const loadFromJSON = async () => {
const blob = await fileOpen({
description: "Excalidraw files",
extensions: ["json", "excalidraw"],
mimeTypes: ["application/json"],
});
return loadFromBlob(blob);
};
Consideraciones sobre la user interface
Whether in Excalidraw or in your application, the user interface must be adapted to the browser support situation. If the native file system API (if ('showOpenFilePicker' in window) {}
) you can show a Save as button at the same time of a Save button. The screenshots below show the difference between Excalidraw's responsive main app toolbar on the iPhone and the Chrome desktop. Note how on iPhone the Save as The button is missing.

Excalidraw app toolbar on iPhone with just one Save button.

Excalidraw application toolbar in Chrome with Save and a focused Save as button.
Conclusions
Working with native files technically works in all modern browsers. In browsers that support the Native File System API, you can improve the experience by allowing true saving and overwriting (not just downloading) of files and by allowing your users to create new files wherever they want, all while remaining functional in browsers that do. it does not support the native file system API. the browser-nativefs It makes your life easier by dealing with the subtleties of progressive enhancement and making your code as simple as possible.
Thanks
This post was reviewed by Joe medley and
Kayce Basques. Thanks to Excalidraw collaborators
for your work on the project and for reviewing my Pull Requests.
Hero image for
Ilya Pavlov on Unsplash.