File System

18 functions for reading, writing, and managing files and directories. All paths are resolved relative to the working directory.

Reading Files

read_text(path) -> string            # entire file as string
read_lines(path) -> list<string>     # list of lines (no trailing \n)
let content = read_text("sample.fasta")
let lines = read_lines("gene_list.txt")
println("Genes:", len(lines))

# Process FASTA line by line
let fasta_lines = read_lines("reference.fa")
let sequences = fasta_lines
  |> filter(|l| not starts_with(l, ">"))
  |> join("")
println("Total bases:", len(sequences))

Writing Files

write_text(path, content) -> string      # returns path
write_lines(path, lines) -> string       # joins with \n
write_text("output.txt", "Analysis complete\n")

let genes = ["BRCA1", "TP53", "EGFR", "KRAS"]
write_lines("significant_genes.txt", genes)

# Generate BED file
let regions = [
  "chr1\t1000\t2000\tgene1",
  "chr7\t5000\t6000\tgene2"
]
write_lines("regions.bed", regions)

glob

Find files matching a glob pattern. Returns a list of matching paths.

glob(pattern) -> list<string>
glob("*.fastq.gz")                    # ["S1_R1.fastq.gz", "S1_R2.fastq.gz"]
glob("data/**/*.bam")                  # recursive search
glob("samples/*/aligned/*.bam")        # wildcard directories

# Process all FASTQ files
let fastqs = glob("raw_data/*.fastq.gz")
println("Found", len(fastqs), "FASTQ files")
for f in fastqs {
  println("Processing:", f)
}

Directory Operations

mkdir(path) -> string          # create directory (recursive), returns path
remove_dir(path, force?) -> nil  # remove directory (force=true for non-empty)
file_exists(path) -> bool      # check if path exists
is_file(path) -> bool          # true if regular file
is_dir(path) -> bool           # true if directory
mkdir("results/alignment/logs")   # creates all intermediate dirs

if not file_exists("output") {
  mkdir("output")
}

assert(is_file("sample.bam"), "BAM file missing")
assert(is_dir("reference/"), "Reference directory missing")

File Operations

file_size(path) -> int            # bytes
copy_file(src, dst) -> string     # returns dst path
rename_file(src, dst) -> string   # returns dst path
remove(path) -> nil               # delete a file
temp_file(suffix?) -> string      # create temp file, return path
temp_dir() -> string              # create temp directory, return path
let size = file_size("genome.fa.gz")
println("Reference size:", round(float(size) / 1e9, 2), "GB")

# Archive results
copy_file("results.csv", "archive/results_20260305.csv")

# Use temp files for intermediate processing
let tmp = temp_file(".bam")
# ... write intermediate BAM to tmp ...
rename_file(tmp, "final_output.bam")

# Clean up
remove("temp_results.txt")

Edge case: remove on a non-existent path raises an error. Use if file_exists(path) { remove(path) } for safe deletion.