Many modern web applications and PWAs allow users select a file from their hard drive, and then save changes back to that file directly.
An old-school approach was to read the file, make the required changes on the server side, and then send the user to a page where they can download the new file. However, this new generation of web apps is able to save the changes directly (no downloads required), and without any server involvement.
How is this possible, and how can I implement something similar?
The File System Access API allows you to open and read files (and even entire directories!) on the user's computer, and then write your changes back. If you choose to open a directory, it even has the ability to create and delete new files and folders within that directory!
A nice introduction to this API can be found on Chrome's website. Otherwise, here's a simple example of how to read a singular file, and then save the changes back directly:
let fileHandle;
async function openFile() {
[fileHandle] = await window.showOpenFilePicker();
// we don't want to handle e.g. folders in this example
if (fileHandle.kind !== "file") {
alert("Please select a file, not a folder");
return;
}
const file = await fileHandle.getFile();
const contents = await file.text();
document.querySelector("#contents").value = contents;
}
async function saveFile() {
// Request permission to edit the file
await fileHandle.requestPermission({ mode: "readwrite" });
const writable = await fileHandle.createWritable();
await writable.write(document.querySelector("#contents").value);
await writable.close();
}
document.querySelector("#openButton").addEventListener("click", openFile);
document.querySelector("#saveButton").addEventListener("click", saveFile);
<p>
<strong>Note: this does work, but StackOverflow's snippets block access to this API--- try it out on your local machine</strong>
</p>
<div>
<button id="openButton">Open</button>
<button id="saveButton">Save</button>
</div>
<textarea id="contents"></textarea>
Key points:
<input type="file" />
or the old .click()
hacks to open one --- window.showOpenFilePicker()
finally provides a nicer built-in API for this, and is a lot more configurable. There's also a window.showSaveFilePicker
you wanted to implement a "save as" or "new file" style capability.