Skip to main content

File module

The File module reads and writes text files and manages folders: open, read, write, copy, rename and delete files, and create and delete folders. On a board, the files go in its flash memory (LittleFS) or on an SD card; on Windows, in two project folders that play the part of the flash and the card.

use File

Platforms​

WindowsESP32 / ESP32-S3ESP32-P4ESP32-S31
flash:The .jxr's folder: Build\flash in an IDE projectThe board's flash memory (LittleFS)SameSame
sd:The sd folder next to it: Build\sdThe SD cardSameSame
File.setUnit("sd:") with no cardAccepts itGives an errorSameSame
The b in the mode ("rb", "wb"…)Doesn't translate line breaks, and lets seek go to any positionChanges nothingSameSame
A mode that isn't in the tableThe VM shuts downOpens for writing if it has w, a or +, and for reading if notSameSame
writeLine ends the line with\r\n (\n if the mode has a b)\r\n\n\n
isEOF()true after a read tries to go past the endtrue as soon as there's nothing left to readSameSame

The board's flash memory is filled with the project's files when you press Run, and the SD card is set up in the board profile: it's all in Display, sound, SD and network.

Run deletes what the program saved in the flash

Each Run on a board writes its whole file memory again with the project's files, and whatever your program wrote to flash: is lost (also with Upload Program). The SD card isn't touched. It's covered in Flash the firmware and run.

Paths and units​

A path can start with the unit, flash: or sd:. Without a unit, it goes to the active unit, which is flash: when the program starts and is changed with File.setUnit.

use File

var f = File.open("flash:data.txt", "w") // in the flash
f.close()

var g = File.open("sd:log.txt", "a") // on the SD card
g.close()

println(File.exists("data.txt")) // true: without a unit, it goes to the flash
  • Folders are separated with /. With or without a leading slash, the path starts at the root of the unit: "data.txt" and "/data.txt" are the same file.
  • In a path without a unit, a flash/ or an sd/ at the start is dropped: "flash/Images/background.bmp" is "Images/background.bmp".
  • Error messages carry the full path: on Windows, the whole folder on disk; on a board, the path from the root, such as /data.txt.

Functions​

FunctionWhat it doesReturns
File.open(path, mode)Opens a fileThe open file
File.exists(path)Checks whether a file or a folder existstrue or false
File.delete(path)Deletes a filetrue
File.rename(path, newPath)Renames a file or moves it, within the same unittrue
File.copy(path, destination)Copies a file, also from one unit to anothertrue
File.isDir(path)Checks whether the path is a foldertrue or false
File.mkDir(path)Creates a foldertrue
File.rmDir(path)Deletes an empty foldertrue
File.size(path)The size of a fileThe bytes, an integer
File.setUnit(unit)Changes the active unittrue
File.getUnit()The active unit"flash:" or "sd:"

If something goes wrong, they throw an exception, which you catch with try (see Errors and exceptions). Besides the errors of each one, all of them except getUnit give ERR_INVALID_ARG_NUMBER if you don't pass the arguments they ask for, and ERR_TYPE_MISMATCH if a path isn't a string.

open(path, mode)​

Opens the file path and returns the open file, with the methods in Returned objects.

ModeWhat for
"r"Read. The file has to exist.
"w"Write. It creates it, or empties it if it already exists.
"a"Append at the end. It creates it if it doesn't exist.
"r+"Read and write. The file has to exist.
"w+"Read and write. It creates it, or empties it if it already exists.
"a+"Read and append at the end.

Any of them can have a b ("rb", "wb", "r+b"…): on Windows, the file is read and written as it is, without changing the line breaks, and seek can go to any position. On the boards, the b changes nothing.

The file's folder has to exist: File.open doesn't create folders.

ErrorWhen
ERR_FILE_NOT_FOUNDIt can't be opened: with "r", the file doesn't exist; with "w" or "a", the folder doesn't exist. The message gives the path and the mode: Could not open file '…' in mode 'r'.
ERR_INVALID_VALUEThe mode isn't in the table, such as "rw" or "x". The message gives the mode.
use File

// Write
var f = File.open("output.txt", "w")
f.writeLine("Hello from JARU")
f.close()

// Read
var g = File.open("output.txt", "r")
println(g.readLine()) // Hello from JARU
g.close()

exists(path)​

Returns true if there's a file or a folder with that path, and false if not.

use File

if (File.exists("config.txt")) then
println("The file exists")
else
println("I can't find it")
end

delete(path)​

Deletes the file path and returns true. If it doesn't exist or can't be deleted, it throws ERR_FILE_NOT_FOUND. To delete a folder, use rmDir.

use File

if (File.exists("temp.txt")) then
File.delete("temp.txt")
end

rename(path, newPath)​

Renames the file path to newPath, or moves it to another folder, and returns true. Both paths have to be on the same unit: to take a file from the flash to the card, use copy and then delete.

ErrorWhen
ERR_INVALID_VALUEThe paths are on different units.
ERR_FILE_NOT_FOUNDIt can't: the file doesn't exist, or the destination folder doesn't exist.
use File

File.rename("draft.txt", "final.txt")

copy(path, destination)​

Copies the file path to destination and returns true. If destination already exists, it replaces it. It can copy from one unit to another.

ErrorWhen
ERR_FILE_NOT_FOUNDThe source file can't be opened, or the destination one can't be created (for instance, because its folder doesn't exist).
ERR_FILE_WRITE_FAILWriting fails halfway (for instance, because the unit fills up).
use File

File.copy("flash:config.txt", "sd:backups/config.txt") // from the flash to the card

isDir(path)​

Returns true if path is a folder, and false if it's a file or doesn't exist.

use File

if (!File.isDir("logs")) then
File.mkDir("logs")
end

mkDir(path)​

Creates the folder path and returns true. It creates a single folder: the one above has to exist. If it can't be created, it throws ERR_FILE_WRITE_FAIL; on Windows, also if it already exists (with the message Directory '…' already exists.). Check first with exists.

use File

if (!File.exists("logs")) then
File.mkDir("logs")
end

rmDir(path)​

Deletes the folder path and returns true. It has to be empty: delete its files first with delete. If it isn't empty or doesn't exist, it throws ERR_FILE_WRITE_FAIL.

use File

File.rmDir("logs/old")

size(path)​

Returns the size of the file path, in bytes. If it doesn't exist, it throws ERR_FILE_NOT_FOUND.

use File

println("It takes ", File.size("data.txt"), " bytes")

setUnit(unit)​

Changes the active unit, the one used by paths without a unit: "flash:" or "sd:". It returns true.

ErrorWhen
ERR_INVALID_VALUEunit isn't "flash:" or "sd:".
ERR_FILE_NOT_FOUNDOn a board, you ask for "sd:" and there's no card mounted. On Windows, "sd:" is always accepted.
use File

File.setUnit("sd:") // from here on, paths without a unit go to the card
var f = File.open("log.txt", "a")
f.writeLine("Log entry")
f.close()

File.setUnit("flash:") // and from here on, to the flash again

getUnit()​

Returns the active unit: "flash:" or "sd:".

use File

println(File.getUnit()) // flash:

Returned objects​

File.open returns the open file. Its methods read and write in it from a position that moves forward with each read or write:

MethodWhat it doesReturns
write(text)Writes a stringThe characters written
writeLine(text)Writes a string and a line breakThe characters written
read()Reads from the position to the endA string
readLine()Reads the next line, without the line breakA string, or nil at the end
seek(pos) / seek(pos, origin)Moves the position0 if it succeeds
position()The position, in bytes from the startAn integer
size()The size of the file, in bytesAn integer
isEOF()Checks whether the end has been reachedtrue or false
isOpen()Checks whether the file is still opentrue or false
close()Closes the filenil

All of them give ERR_INVALID_ARG_NUMBER if you don't pass the arguments they ask for. After close(), all except isOpen and close give an error: ERR_FILE_WRITE_FAIL when writing, ERR_FILE_READ_FAIL when reading and ERR_INVALID_OPERATION in the rest.

write(text)​

Writes the string text to the file and returns how many characters it wrote. text has to be a string: to write a number, convert it first with toString().

If the file was opened with "r", it throws ERR_FILE_WRITE_FAIL (File was opened in read-only mode ('r').).

writeLine(text)​

Like write, and it also ends the line. On Windows and on the ESP32 and ESP32-S3, the line ends in \r\n; on the P4 and the S31, in \n. readLine understands both.

use File

var f = File.open("list.txt", "w")
f.writeLine("first")
f.writeLine("second")
f.close()

read()​

Reads from the position to the end of the file and returns it in a string. To read the whole file, call it right after opening it, or after seek(0).

readLine()​

Reads the next line and returns it without the line break, be it \n or \r\n. At the end, it returns nil. The last line is read even if it doesn't end in a line break.

use File

var f = File.open("list.txt", "r")
var line = f.readLine()
while (line != nil)
println(line)
line = f.readLine()
end
f.close()

seek(pos, origin)​

Moves the position to pos bytes from the start, which is the default. With origin it measures from somewhere else: 0, the start; 1, the current position; 2, the end (with a negative pos to go backwards). An origin that isn't any of those counts as 0.

It returns 0 if it succeeds and another number if not. pos and origin have to be integers (ERR_TYPE_MISMATCH).

On Windows, if the mode has no b, it can only go to position 0: with any other, it throws ERR_INVALID_OPERATION. Open the file with "rb" to go to any position.

use File

var f = File.open("list.txt", "rb")
f.seek(-8, 2) // 8 bytes before the end
println(f.position())
f.close()

position()​

Returns the position, in bytes from the start of the file.

size()​

Returns the size of the open file, in bytes, without moving the position. It's the same as File.size with its path.

isEOF()​

Returns true if the end of the file has been reached.

On Windows it turns true after a read tries to go past the end: after reading the last line with readLine it's still false, and it turns true when readLine returns nil. On the boards it turns true as soon as there's nothing left to read. To go through a file, look at what readLine returns, not at isEOF().

isOpen()​

Returns true if the file is open, and false after close().

close()​

Closes the file and returns nil. What you wrote stays on the disk or in the flash. Closing it again does nothing.

Complete example​

An event log: it adds lines with the time to a file, reads it whole and says how much it takes.

use File

// The log folder
if (!File.exists("logs")) then
File.mkDir("logs")
end

func note(message)
var f = File.open("logs/log.txt", "a")
f.writeLine("[" + time() + "] " + message)
f.close()
end

func show()
if (!File.exists("logs/log.txt")) then
println("There's no log yet")
return
end
var f = File.open("logs/log.txt", "r")
var line = f.readLine()
while (line != nil)
println(line)
line = f.readLine()
end
f.close()
end

note("System started")
note("Sensor active")
note("Temperature: 23.5 degrees")

show()
println("The log takes ", File.size("logs/log.txt"), " bytes")

The first time, on Windows, it prints something like this (the time is the current one; time() gives it as text):

[Fri Nov  6 19:45:41 2026] System started
[Fri Nov 6 19:45:41 2026] Sensor active
[Fri Nov 6 19:45:41 2026] Temperature: 23.5 degrees
The log takes 139 bytes

Each time you run it, the log grows: "a" appends at the end.

Pitfalls and known issues​

  • Text only. write and writeLine write strings, and a string is cut at the first 0 byte: the module isn't for writing binary data. read does return every byte.
  • seek on Windows, with b. Without the b in the mode, seek only goes to position 0.
  • There's no way to list a folder. The module has no function that tells which files there are: keep the names yourself, for instance in an index file.
  • Folders, one at a time. Neither mkDir nor open create the folders above.
  • Close your files. Until close(), what you wrote may not be in the flash or on the card yet.

All the known issues of JARU, together, are in Known issues.