Files
Why files?
So far, all our programs lose their data when they finish running. Variables only exist while the program is alive. But what if you want to save a high score, store a configuration, or process a log? That is where files come in.
Files let your programs persist data — save it to disk so it survives after the program exits, and read it back later.
Reading a file
The simplest operation is reading an entire file into a string:
import { read_file } from "std/file" fn main() { let content: String = read_file("message.txt") print(content) }
If message.txt contains Hello from a file!, the program prints exactly that.
read_file returns the entire file as a single string, including newlines. This is the easiest way to get data from a file.
Writing a file
To save data, use write_file:
import { write_file } from "std/file" fn main() { write_file("output.txt", "Nyx was here!") print("File written successfully") }
This creates output.txt (or overwrites it if it already exists) with the text Nyx was here!.
write_file returns 1 on success.
Checking if a file exists
Before reading a file, you might want to check if it actually exists:
import { read_file, file_exists } from "std/file" fn main() { if file_exists("config.txt") { let config: String = read_file("config.txt") print("Config loaded: " + config) } else { print("No config file found, using defaults") } }
file_exists returns true if the file is on disk, false otherwise.
Working with lines
Files often contain multiple lines of data. You can use .split() to break the content into lines:
import { read_file } from "std/file" fn main() { let content: String = read_file("names.txt") let lines: Array = content.split("\n") var i: int = 0 while i < lines.length() { print("Line " + int_to_string(i + 1) + ": " + lines[i]) i += 1 } }
If names.txt contains:
Alice Bob Charlie
Output:
Line 1: Alice Line 2: Bob Line 3: Charlie
Writing multiple lines
To write multiple lines, join them with newline characters:
import { write_file } from "std/file" fn main() { let names: Array = ["Alice", "Bob", "Charlie", "Diana"] var content: String = "" var i: int = 0 while i < names.length() { content = content + names[i] + "\n" i += 1 } write_file("names.txt", content) print("Wrote " + int_to_string(names.length()) + " names") }
Practical example: a simple config file
Many programs use config files to store settings. Let's build a simple key=value config reader:
import { read_file, write_file, file_exists } from "std/file" fn load_config(path: String) -> Map { var config: Map = Map.new() if file_exists(path) { let content: String = read_file(path) let lines: Array = content.split("\n") var i: int = 0 while i < lines.length() { let line: String = lines[i] let eq_pos: int = line.indexOf("=") if eq_pos > 0 { let key: String = line.substring(0, eq_pos) let value: String = line.substring(eq_pos + 1, line.length()) config.insert(key, value) } i += 1 } } return config } fn save_config(path: String, config: Map) { var content: String = "" // We save known keys if config.contains("host") { content = content + "host=" + config.get("host") + "\n" } if config.contains("port") { content = content + "port=" + config.get("port") + "\n" } if config.contains("debug") { content = content + "debug=" + config.get("debug") + "\n" } write_file(path, content) } fn main() { let config: Map = load_config("app.conf") if config.contains("host") { print("Host: " + config.get("host")) } else { print("No config found, creating defaults...") var defaults: Map = Map.new() defaults.insert("host", "localhost") defaults.insert("port", "8080") defaults.insert("debug", "false") save_config("app.conf", defaults) print("Default config saved to app.conf") } }
Practical example: a simple logger
import { read_file, write_file, file_exists } from "std/file" fn log_message(path: String, message: String) { var content: String = "" if file_exists(path) { content = read_file(path) } content = content + message + "\n" write_file(path, content) } fn main() { let log_file: String = "app.log" log_message(log_file, "Application started") log_message(log_file, "Processing data...") log_message(log_file, "Done!") print("Log contents:") print(read_file(log_file)) }
Output:
Log contents: Application started Processing data... Done!
Practical example: CSV data processing
CSV (Comma-Separated Values) is a common file format. Let's read and process one:
import { read_file } from "std/file" struct Product { name: String, price: int, quantity: int } fn parse_csv(content: String) -> Array { let lines: Array = content.split("\n") var products: Array = [] // Skip header line, start at 1 var i: int = 1 while i < lines.length() { let line: String = lines[i] if line.length() > 0 { let fields: Array = line.split(",") let p: Product = Product { name: fields[0], price: string_to_int(fields[1]), quantity: string_to_int(fields[2]) } products.push(p) } i += 1 } return products } fn main() { // Assume inventory.csv contains: // name,price,quantity // Apple,2,50 // Bread,3,20 // Milk,4,30 let content: String = read_file("inventory.csv") let products: Array = parse_csv(content) var total_value: int = 0 var i: int = 0 while i < products.length() { let p: Product = products[i] let value: int = p.price * p.quantity print(p.name + ": $" + int_to_string(value)) total_value += value i += 1 } print("Total inventory value: $" + int_to_string(total_value)) }
Exercises
- Write a program that reads a file of numbers (one per line) and prints the sum, average, minimum, and maximum.
- Write a "todo list" program that saves tasks to
todos.txt. It should be able to add a task (append a line) and display all tasks (read and print).
- Write a program that reads a text file and counts how many times each word appears. Print the word counts.
- Write a program that copies one file to another: read the source, write to the destination, and print a confirmation message.
- Write a program that reads a CSV with student names and grades, calculates the average for each student, and writes a summary report to a new file.
Summary
read_file(path)reads an entire file into a string.write_file(path, content)writes a string to a file (creates or overwrites).file_exists(path)checks if a file exists on disk.- Use
.split("\n")to break file content into lines. - Use string concatenation with
"\n"to build multi-line content. - Files let your programs save and load data that persists across runs.
Next chapter: Closures and first-class functions →