In this article, I will show how to use the File System Access API. This API is a web platform API that enables developers to build powerful web apps that interact with files on the user’s local device. There are a few caveats in using this API such as accessing local files requires user interaction, such as clicking a button.
These APIs are not yet supported by all browsers. Chrome, Edge, and Opera support them, but Brave, Firefox and Safari do not. You can check compatibility here. Writing Python code is easy. Developing applications that support a wide range of environments can be a challenge.
If you are targeting the desktop version of Chrome or Edge, this is the API to use. If you are targeting Firefox or mobile devices, you must use the older FileReader APIs I wrote about in Part 1.
I have put each example in this article on my website. My examples can be downloaded using wget
, curl
, or by right-clicking on the page and selecting view page source. You can also right-click on the link and select Save link as.
Examples:
Part 1 of this series.
Feature Availability Check
It is a good idea to check if the File System Access API is available as some browsers do not support it.
1 2 3 4 5 6 7 |
def feature_check(): if hasattr(window, 'showOpenFilePicker'): console.log('showOpenFilePicker present') else: console.log('showOpenFilePicker is not present') # Do something here to let the user know or # fallback to the FileReader class |
Local File Read
To read a local file requires using the showOpenFilePicker()
. This function must be called in an event handler from a user action such as clicking a button. This code demonstrates the error if you try to call it directly:
1 2 3 4 5 6 |
async def select_file(): try: fileHandles = await window.showOpenFilePicker(); except Exception as e: console.log('Exception: ' + str(e)) return |
An exception will be generated:
1 |
SecurityError: Failed to execute 'showOpenFilePicker' on 'Window': Must be handling a user gesture to show a file picker. |
One solution is to create a button that calls an event handler when clicked.
1 |
<button class="button" type="button" id="file_select">Read Local File</button> |
Specify the required imports:
1 2 3 |
import asyncio from js import document, Object, window from pyodide import create_proxy, to_js |
Create a proxy to manage the interface from JavaScript to Python and attach it to the button:
1 2 3 4 5 6 |
def setup_button(): # Create a Python proxy for the callback function file_select_proxy = create_proxy(file_select_event) # Set the listener to the callback document.getElementById("file_select").addEventListener("click", file_select_proxy, False) |
Create the function to be called when the user clicks the button:
1 2 3 4 5 6 |
async def file_select_event(event): try: fileHandles = await window.showOpenFilePicker(); except Exception as e: console.log('Exception: ' + str(e)) return |
The showOpenFilePicker()
function returns a FileSystemFileHandle sequence. The user can select one or many files.
To allow the user to select multiple files:
1 2 3 4 5 |
options = { "multiple": True } fileHandles = await window.showOpenFilePicker(Object.fromEntries(to_js(options))); |
You can also specify filter options. For example, to open the file picker in the Documents folder:
1 2 3 |
options = { "startIn": "documents" } |
See this link for more information about “WellKnownDirectory” options and this link for file picker options.
You can fetch details about the selected file such as file name and size. Let’s console.log
those properties. At this time, you cannot use the Python print()
statement in event handlers.
1 2 3 4 |
console.log(file.name) console.log(file.size) console.log(file.type) console.log(file.lastModifiedDate) |
To read the file data, call file.text()
:
1 |
content = await file.text() |
I put a complete example on my website: fsa_example_1.html
Local File Write
To select/create a local file requires using the showSaveFilePicker()
. This function must be called in an event handler from a user action such as clicking a button.
If you try to call showSaveFilePicker()
without directly, the browser will display an error in the debugger Console window similar to:
1 |
Exception: SecurityError: Failed to execute 'showSaveFilePicker' on 'Window': Must be handling a user gesture to show a file picker. |
This function will create a file. If nothing further is done with the file returned by this function, the length will be 0 bytes.
1 2 3 4 5 |
try: fileHandle = await window.showSaveFilePicker() except Exception as e: console.log('Exception: ' + str(e)) return |
The showSaveFilePicker()
function supports options. For example, to start in the Documents folder and suggest a filename to save to:
1 2 3 4 5 6 7 8 9 10 |
try: options = { "startIn": "documents", "suggestedName": "testfile.txt" } fileHandle = await window.showSaveFilePicker(Object.fromEntries(to_js(options))) except Exception as e: console.log('Exception: ' + str(e)) return |
To write data to the file, get a writable handle:
1 2 3 4 5 |
content = "This is a test file data" file = await fileHandle.createWritable() await file.write(content) await file.close() |
Do not forget to close the file handle.
I put a complete example on my website: fsa_example_2.html
For browsers that do not support the showSaveFilePicker() API, use the following code:
1 2 3 4 5 6 7 8 |
from js import Blob, document, URL # content is the data to write to a file content = 'Hello world' tag = document.createElement('a') blob = Blob.new([content], {type: "text/plain"}) tag.href = URL.createObjectURL(blob) tag.download = 'filename' tag.click() |
This technique creates an HTML anchor and attaches data to the anchor as an href
. This code does not require user interaction to execute such as a button click.
Summary
This article covered the basics of using the File System Access API. The is an easy to use interface to the local file system. If the desktop has drivers installed for services such as Microsoft One Drive or Google Drive, you can select them as a save file destination.
More Information
- Other articles that I have written on Pyscript
- showOpenFilePicker()
- showSaveFilePicker()
- FileSystemFileHandle
- Can I Use
Photography Credit
I write free articles about technology. Recently, I learned about Pexels.com which provides free images. The image in this article is courtesy of Djalma Paiva Armelin at Pexels.
I design software for enterprise-class systems and data centers. My background is 30+ years in storage (SCSI, FC, iSCSI, disk arrays, imaging) virtualization. 20+ years in identity, security, and forensics.
For the past 14+ years, I have been working in the cloud (AWS, Azure, Google, Alibaba, IBM, Oracle) designing hybrid and multi-cloud software solutions. I am an MVP/GDE with several.
1 Pingback