JFS (Jumperless FileSystem)
The jfs module is basically like MicroPython's vfs and parts of os, but kinda written in a style that's probably more familiar to Arduino-style C++ people (me). It uses the almost standardized API shared by FatFS (the one Jumperless actually uses), LittleFS, and SDFS, but still has been Pythonified to use types that are easier to work with in MicroPython.
Quick Reference
File Operations:
jfs.open(path, mode)- Opens file, returns file handlejfs.read(file, size=1024)- Read from filejfs.write(file, data)- Write to filejfs.close(file)- Close filejfs.seek(file, position, whence=0)- Seek in filejfs.tell(file)- Get current positionjfs.size(file)- Get file sizejfs.available(file)- Get bytes available
File Object Methods (after f = jfs.open(...)):
f.print(data)- Print to the file (likewritebut auto-flushes)f.flush()- Flush buffered data to filef.position()- Alias forf.tell()f.name()- Get file name
Directory Operations:
jfs.exists(path)- Check if path exists (returns True/False)jfs.listdir(path)- List directory contents (returns list)jfs.mkdir(path)- Create directoryjfs.rmdir(path)- Remove directoryjfs.remove(path)- Remove filejfs.rename(from, to)- Rename/move filejfs.stat(path)- Get file/directory status info
Filesystem Info:
jfs.info()- Returns (total, used, free) tuple
Usage
import jfs #you don't actually need this, jfs is imported globally by default
# List files in the root directory
files = jfs.listdir('/') # returns a python list
print(files)
['config.txt', 'nodeFileSlot0.txt', 'python_scripts/', 'nodeFileSlot1.txt', 'nodeFileSlot2.txt', 'nodeFileSlot3.txt', 'nodeFileSlot4.txt', 'nodeFileSlot5.txt', 'nodeFileSlot6.txt', 'nodeFileSlot7.txt', 'net_colors/']
If you want to make this print with subdirectories
files = jfs.listdir('/')
for file in range(len(files)):
print(files[file])
if files[file].endswith("/"):
subdir = jfs.listdir(files[file])
for i in range(len(subdir)):
print(" - " + subdir[i])
nodeFileSlot0.txt
python_scripts/
- history.txt
- examples/
- fake_gpio.py
- _temp_repl_edit.py
- Hey.txt
- script_1.py
- script_2.py
- script_3.py
- log.txt
- lib/
- script_4.py
- pathtest.py
nodeFileSlot1.txt
nodeFileSlot2.txt
nodeFileSlot3.txt
nodeFileSlot4.txt
nodeFileSlot5.txt
nodeFileSlot6.txt
nodeFileSlot7.txt
net_colors/
- netColorsSlot0.txt
File API
File objects returned by jfs.open() support method calls directly on the object:
# Object-oriented file operations
# Write-only mode
f = jfs.open('hello.txt', 'w')
f.write('Hello, Jumperless!')
f.close()
# Read from the file (need to reopen or use w+/r+ mode)
f = jfs.open('hello.txt', 'r')
content = f.read() # Read from file object
size = f.size() # Get file size
f.close()
# Read-write mode (truncates file)
f = jfs.open('hello.txt', 'w+')
f.write('Hello, Jumperless!')
f.seek(0) # Seek to beginning to read what we wrote
content = f.read() # Now this works!
f.close()
# Context manager support (automatically closes file)
with jfs.open('data.txt', 'w+') as f:
f.write('This file will be automatically closed')
f.seek(0) # Reset to beginning
content = f.read() # Read back what we wrote
pos = f.tell() # Get current position
name = f.name() # Get file name
Using f.print() for logging
The f.print() method works like Python's print() but writes to the file. It automatically converts arguments to strings and flushes after each call - perfect for logging:
# Great for logging - auto-converts types and flushes immediately
with jfs.open('log.txt', 'w+') as f:
f.print("Starting test...")
voltage = adc_get(0)
f.print("Voltage:", voltage, "V") # Multiple args work
f.print("Test complete!")
# Unlike f.write(), f.print() handles non-strings automatically
f = jfs.open('data.txt', 'w')
f.print(123) # OK - converts int to string
f.print(3.14) # OK - converts float to string
f.print("mixed", 42) # OK - multiple args joined with spaces
f.close()
Note: f.print() is a file object method only. There is no jfs.print() module-level function.
Other ways to do the same thing
### 2. Module-Level Functions You can also use module-level functions with file handles:f = jfs.open('hello.txt', 'w')
jfs.write(f, 'Hello, Jumperless!') # Module-level function
jfs.seek(f, 0) # Module-level function
content = jfs.read(f) # Module-level function
jfs.close(f) # Module-level function
# Write/read entire files at once (no file handles needed)
jfs.write('config.txt', 'key=value\nother=setting')
content = jfs.read('config.txt')
File Modes
When using jfs.open(path, mode), the following modes are supported:
| Mode | Description | Read | Write | Create |
|---|---|---|---|---|
'r' |
Read only | ✅ | ❌ | ❌ |
'w' |
Write only | ❌ | ✅ | ✅ |
'a' |
Append only | ❌ | ✅ | ✅ |
'r+' |
Read + Write | ✅ | ✅ | ❌ |
'w+' |
Read + Write | ✅ | ✅ | ✅ |
'a+' |
Read + Append | ✅ | ✅ | ✅ |
Important: You cannot read from a file opened in write-only mode ('w' or 'a'). Use 'w+', 'r+', or 'a+' if you need both read and write access.
Open a file for writing
f = jfs.open('hello.txt', 'w')
f.write('Hello, Jumperless!') # Now works with object-oriented API!
f.close()
Directory Operations
jfs.listdir(path)
Returns a list containing the names of the entries in the directory given by path.
path(str): The path to the directory.
Example:
# List contents of the root directory
print(jfs.listdir('/'))
# List contents of a subdirectory
jfs.mkdir('/my_dir')
print(jfs.listdir('/my_dir'))
jfs.mkdir(path)
Create a new directory.
path(str): The path of the new directory.
jfs.rmdir(path)
Remove an empty directory.
path(str): The path of the directory to remove.
jfs.remove(path)
Remove a file.
path(str): The path of the file to remove.
jfs.rename(old_path, new_path)
Rename a file or directory.
old_path(str): The current path.new_path(str): The new path.
jfs.exists(path)
Check if a file or directory exists.
path(str): The path to check.- Returns
Trueif it exists,Falseotherwise.
jfs.stat(path)
Get status of a file or directory.
path(str): The path of the file or directory.- Returns a tuple with file information (mode, size, etc.), similar to
os.stat().
Filesystem Information
jfs.info()
Get information about the filesystem.
- Returns a tuple
(total_bytes, used_bytes, free_bytes).
Example:
total, used, free = jfs.info()
print("Filesystem Size: " + str(total / 1024) + " KB")
print("Used: " + str(used / 1024) + " KB")
print("Free: " + str(free / 1024) + " KB")
File I/O
The jfs module supports standard file opening and handling using jfs.open() and file objects, including support for the with statement for automatic resource management.
jfs.open(path, mode='r')
Open a file and return a corresponding file object.
path(str): The path to the file.mode(str, optional): The mode in which the file is opened. Defaults to'r'.'r': Read (default).'w': Write (creates a new file or truncates an existing one).'a': Append.'r+': Read and write.'w+': Write and read (creates/truncates).'a+': Append and read.
Example:
# Open a file for reading
f = jfs.open('config.txt', 'r')
content = f.read()
f.close()
# Use 'with' for automatic closing
with jfs.open('data.log', 'a') as log_file:
log_file.write('New log entry.\\n')
File Object Methods
The file object returned by jfs.open() has the following methods:
file.read([size])
Read size bytes from the file. If size is omitted or negative, the entire file is read.
file.write(data)
Write the given string or bytes data to the file. Returns the number of bytes written.
file.close()
Close the file. A closed file cannot be read or written to.
file.seek(offset, [whence])
Change the stream position.
* offset: The byte offset.
* whence (optional):
* 0: Seek from the start of the stream (default). Use jfs.SEEK_SET.
* 1: Seek from the current position. Use jfs.SEEK_CUR.
* 2: Seek from the end of the stream. Use jfs.SEEK_END.
file.tell()
Return the current stream position.
* Aliases: file.position()
file.size()
Return the total size of the file in bytes.
file.available()
Return the number of bytes available to be read from the current position to the end of the file.
file.name
Returns the name of the file.
Module-Level File Operations
For convenience, the jfs module also provides functions that operate directly on file handles returned by jfs.open(). This can be useful in some scripting scenarios but using file object methods is generally preferred for clarity.
jfs.read(file_handle, [size])jfs.write(file_handle, data)jfs.close(file_handle)jfs.seek(file_handle, offset, [whence])jfs.tell(file_handle)jfs.size(file_handle)jfs.available(file_handle)
Example:
file_handle = jfs.open('temp.txt', 'w')
jfs.write(file_handle, 'some data')
jfs.close(file_handle)