Skip to main content

I/O Operations

File and console I/O in Oxide uses Rust's standard library directly. This page documents common I/O patterns using Oxide syntax.

File I/O

File operations use Rust's std::fs module:

Reading Files

import std.fs

fn main() {
// Read entire file to string
let content = fs.readToString("config.txt")
match content {
Ok(text) -> println!("Content: $text")
Err(e) -> println!("Error: $e")
}

// With try? - returns optional
let content = try? fs.readToString("config.txt")
if let text = content {
println!("Content: $text")
}

// With do-catch
do {
let content = try fs.readToString("data.txt")
process(content)
} catch {
println!("Error reading file: $error")
}
}

Writing Files

import std.fs

fn main() {
// Write string to file
do {
try fs.write("output.txt", "Hello, World!")
println!("File written successfully")
} catch {
println!("Error writing: $error")
}
}

Checking File Existence

import std.path.Path

fn main() {
let path = Path.new("config.toml")
if path.exists() {
let config = try? fs.readToString("config.toml")
// process config
} else {
println!("Config not found, using defaults")
}
}

Reading Lines

import std.fs
import std.io.BufRead
import std.io.BufReader

fn main() {
do {
let file = try fs.File.open("data.txt")
let reader = BufReader.new(file)

for line in reader.lines() {
match line {
Ok(text) -> println!("Line: $text")
Err(e) -> println!("Error: $e")
}
}
} catch {
println!("Error: $error")
}
}

Console I/O

Printing

fn main() {
// Print with newline
println!("Hello, World!")

// Print without newline
print!("Enter name: ")

// Debug print
let numbers = [1, 2, 3]
println!("Numbers: #numbers") // Uses {:?} format
}

Reading User Input

import std.io
import std.io.BufRead

fn main() {
print!("Enter your name: ")
io.stdout().flush() // Ensure prompt is displayed

var input = String.new()
io.stdin().readLine(&mut input)
let name = input.trim()

println!("Hello, $name!")
}

Practical Examples

Config File Reading

import std.fs
import std.path.Path

struct Config(
host: String,
port: Int,
debug: Bool
)

fn loadConfig(path: String): Config {
let defaults = Config(
host = "localhost",
port = 8080,
debug = false
)

guard Path.new(path).exists() else {
return defaults
}

let content = try? fs.readToString(path) ?? ""

// Parse simple key=value format
var config = defaults
for line in content.lines() {
let parts: Array<&str> = line.split("=").collect()
if parts.len() == 2 {
let key = parts[0].trim()
let value = parts[1].trim()

match key {
"host" -> config.host = value.toString()
"port" -> config.port = value.parse<Int>().unwrapOr(8080)
"debug" -> config.debug = value == "true"
else -> ()
}
}
}

config
}

Logging to File

import std.fs.OpenOptions
import std.io.Write

fn log(message: String) {
let entry = "[LOG] $message\n"

do {
var file = try OpenOptions.new()
.append(true)
.create(true)
.open("app.log")
try file.writeAll(entry.asBytes())
} catch {
eprintln!("Failed to write log: $error")
}
}

fn main() {
log("Application started")
// ... application code ...
log("Application finished")
}

Interactive Input Loop

import std.io
import std.io.BufRead

fn readValidNumber(): Int {
loop {
print!("Enter a positive number: ")
io.stdout().flush()

var input = String.new()
io.stdin().readLine(&mut input)

if let num = input.trim().parse<Int>().ok() {
if num > 0 {
return num
}
}

println!("Invalid input, try again")
}
}

Error Handling Patterns

Using try?

Best for optional results where errors can be handled with defaults:

let content = try? fs.readToString("optional.txt")
let text = content ?? "default content"

Using try!

For situations where failure indicates a bug or unrecoverable state:

// In tests
let testData = try! fs.readToString("test_fixtures/data.json")

// Required files
let required = try! fs.readToString("critical.conf")

Using do-catch

For comprehensive error handling:

fn processFiles(paths: Array<String>) {
for path in paths {
do {
let content = try fs.readToString(path)
let result = try process(content)
try fs.write("output_$path", result)
} catch {
println!("Error processing $path: $error")
// Continue with next file
}
}
}

Comparison with Rust

OxideRust
fs.readToString(p)std::fs::read_to_string(p)
fs.write(p, c)std::fs::write(p, c)
Path.new(p).exists()std::path::Path::new(p).exists()
io.stdin().readLine(&mut s)std::io::stdin().read_line(&mut s)
file.writeAll(b)file.write_all(b)

See Also