io

Whole-file reads and writes, and line input from the console.

Oxigen
introduce io
FunctionSignatureReturns
read_fileread_file(path)str
write_filewrite_file(path, content)None
append_fileappend_file(path, content)None
read_bytesread_bytes(path)array of byte
write_byteswrite_bytes(path, data)None
file_existsfile_exists(path)bool
file_sizefile_size(path)int bytes
inputinput(prompt)str
read_lineread_line()str

read_file and write_file work with UTF-8 text: a file is one string. For a binary file, use read_bytes and write_bytes, which work with arrays of bytes. There is no streaming reader. For a large or binary download, stream it straight to disk with net.download instead of building it in memory.

Directory work (create, list, walk, delete) lives in os; path string manipulation lives in path.


#Files

#read_file(path)

Read the whole file into a string. A missing or unreadable file is an Error that halts the program unless you normalize it.

Oxigen
introduce io

println(io.read_file("notes.txt"))

Handling a missing file rather than aborting:

Oxigen
introduce io

r := <type<Error> || <Value>>(io.read_file("maybe.txt"))
text := option {
    is_error(r) -> { "" }
    { r.value }
}
println(len(text))     // 0
println(r.msg)         // No such file or directory (os error 2)

The simpler guard is to ask first:

Oxigen
option {
    io.file_exists("notes.txt") -> { println(io.read_file("notes.txt")) }
    { println("no notes yet") }
}

#write_file(path, content)

Write a string to a file, replacing whatever was there. Creates the file if it does not exist; the parent directory must already exist (see os.mkdir).

Oxigen
io.write_file("test.txt", "Hello!")
println(io.read_file("test.txt"))   // Hello!

#append_file(path, content)

Append to the end of a file, creating it if needed. No newline is added — put one in the string yourself.

Oxigen
io.append_file("log.txt", "started\n")
io.append_file("log.txt", "finished\n")

#read_bytes(path)

The file's raw contents, as an array of byte values. For binary files that read_file cannot hold as text:

Oxigen
introduce io

data := io.read_bytes("photo.jpg")
println(len(data))                       // the size in bytes
println(data[0] == byte(255))            // True: a JPEG starts FF D8

Each byte takes the room of a full value in an array, so this suits small binary files (headers, icons, short clips), not large ones. Move large files with net.download or os.exec_argv("cp", ...).

#write_bytes(path, data)

Write an array of bytes, or ints from 0 to 255, to a file exactly as given, replacing what was there:

Oxigen
io.write_bytes("magic.bin", [127, 69, 76, 70])   // the ELF header, \x7F E L F

Anything else in the array is an error, and nothing is written.

#file_exists(path)

Oxigen
println(io.file_exists("test.txt"))   // True
println(io.file_exists("nope.txt"))   // False

This answers only "is there something readable at this path". Use os.is_file / os.is_dir when the distinction matters.


#Console input

#file_size(path)

The size of a file in bytes, or an IO error value when it cannot be read.

Oxigen
println(io.file_size("test.txt"))   // 13

#input(prompt)

Print prompt (no newline), then read one line from stdin. The trailing newline is not included.

Oxigen
introduce io

name := io.input("What is your name? ")
println("Hello, {name}!")

Everything comes back as a string — convert it yourself:

Oxigen
age := int(io.input("Age: "))
println(age + 1)

#read_line()

Read one line from stdin with no prompt. This is how you consume piped input.

Oxigen
// echo.oxi — repeat every piped line, uppercased
introduce io
introduce strings

line := io.read_line()
repeat unless line == "" {
    println(strings.upper(line))
    line = io.read_line()
}
$ printf 'a\nb\n' | oxigen echo.oxi
A
B

At end of input read_line returns "".


#Worked example

Oxigen
introduce io
introduce json
introduce os

// Append a line to a log, rotating it once it gets long.
fun log_line(path <str>, msg <str>) {
    option {
        io.file_exists(path) and len(io.read_file(path)) > 1000 -> {
            io.write_file(path + ".old", io.read_file(path))
            io.write_file(path, "")
        }
    }
    io.append_file(path, msg + "\n")
}

log_line("app.log", "started")
print(io.read_file("app.log"))   // started
os.remove_file("app.log")

See also: os for directories and processes, path for path strings, json / toml for read/write helpers that parse as they load.