IOUtilsLib — I/O Utilities Library

Comprehensive file and directory operations for Plan9Basic. Based on Delphi’s System.IOUtils unit (TFile, TDirectory, TPath). Fully cross-platform: Windows, macOS, Linux, Android, and iOS. 53 functions.

CategoryCountDescription
Error Handling2ioerror, iostrerror$
File Reading3file_readalltext$ (2 overloads), file_readallbytes#
File Writing6file_writealltext (2), file_appendalltext (2), file_writeallbytes, file_createempty
File Operations6file_copy (2), file_move, file_delete, file_exists, file_getsize
File Timestamps6get/set creation, access, and write times
Directory Ops7dir_create, dir_delete (2), dir_exists, dir_move, dir_copy, dir_isempty
Directory Listing8dir_getfiles$ (3), dir_getdirectories$ (3), dir_getentries$ (2)
Directory Info5dir_getcurrent$, dir_setcurrent, dir_getparent$, dir_isrelativepath, + timestamps (6)
Path Manipulation8path_combine$ (2), components (6)
Path Validation6path_ispathrooted, isrelativepath, hasvalidpathchars, hasvalidfilenamechars, matchespattern (2)

Error Handling

CodeDescription
0No error
1File not found
2Directory not found
3Access denied
4Path too long
5Invalid path
6I/O error
7File already exists
8Directory not empty
9Invalid argument
10Unknown error
FunctionSignatureDescription
ioerror()ioerror@Last error code (0–10)
iostrerror$()iostrerror$@Descriptive error message
╯ plan9basic
let content$ = file_readalltext$("missing.txt")
if ioerror() <> 0 then
    println "Error: "; iostrerror$()
endif

File Reading

FunctionSignatureDescription
file_readalltext$(path$)file_readalltext$@$Read entire file as UTF-8 text
file_readalltext$(path$, enc$)file_readalltext$@$$Read file with specified encoding
file_readallbytes#(path$)file_readallbytes#@$Read file as byte stream (TMemoryStream)
EncodingDescription
utf-8Default, recommended for most files
utf-7Legacy UTF-7 encoding
ansiSystem default ANSI encoding
ascii7-bit ASCII
unicodeUTF-16 Little Endian
utf-16beUTF-16 Big Endian
╯ plan9basic
' Read UTF-8 (default)
let content$ = file_readalltext$("data.txt")
if ioerror() <> 0 then
    println "Read error: "; iostrerror$()
endif

' Read with specific encoding
let latin$ = file_readalltext$("latin.txt", "ansi")

' Read binary file
let stream# = file_readallbytes#("image.png")

File Writing

FunctionSignatureDescription
file_writealltext(path$, content$)file_writealltext@$$Write text to file (UTF-8)
file_writealltext(path$, content$, enc$)file_writealltext@$$$Write with encoding
file_appendalltext(path$, content$)file_appendalltext@$$Append text (UTF-8)
file_appendalltext(path$, content$, enc$)file_appendalltext@$$$Append with encoding
file_writeallbytes(path$, stream#)file_writeallbytes@$#Write byte stream to file
file_createempty(path$)file_createempty@$Create empty file or update timestamp
╯ plan9basic
' Write text file
let result = file_writealltext("output.txt", "Hello, World!")

' Append to log
let logline$ = formatdatetime$("yyyy-mm-dd hh:nn:ss", now()) + " - Event"
let result = file_appendalltext("log.txt", logline$ + chr$(13) + chr$(10))

' Write with specific encoding
let result = file_writealltext("data.csv", "Name;Value", "ansi")

File Operations

FunctionSignatureDescription
file_copy(src$, dst$)file_copy@$$Copy file (fails if destination exists)
file_copy(src$, dst$, overwrite)file_copy@$$nCopy with overwrite option (1=overwrite)
file_move(src$, dst$)file_move@$$Move or rename file
file_delete(path$)file_delete@$Delete file
file_exists(path$)file_exists@$File exists? (1/0)
file_getsize(path$)file_getsize@$File size in bytes
╯ plan9basic
' Copy with overwrite
if file_exists("source.txt") <> 0 then
    let result = file_copy("source.txt", "backup.txt", 1)
endif

' Move / rename
let result = file_move("old.txt", "new.txt")

' Delete
let result = file_delete("temp.txt")
if ioerror() <> 0 then
    println "Could not delete: "; iostrerror$()
endif

' Get size
let size = file_getsize("document.pdf")
println "Size: "; size; " bytes"

File Timestamps

FunctionSignatureDescription
file_getcreationtime(path$)file_getcreationtime@$Creation time (TDateTime)
file_getlastaccesstime(path$)file_getlastaccesstime@$Last access time
file_getlastwritetime(path$)file_getlastwritetime@$Last modification time
file_setcreationtime(path$, dt)file_setcreationtime@$nSet creation time
file_setlastaccesstime(path$, dt)file_setlastaccesstime@$nSet last access time
file_setlastwritetime(path$, dt)file_setlastwritetime@$nSet modification time
╯ plan9basic
' Get modification time
let modified = file_getlastwritetime("document.txt")
println "Modified: "; formatdatetime$("yyyy-mm-dd hh:nn:ss", modified)

' Update modification time to now
let result = file_setlastwritetime("document.txt", now())
ⓘ Note: Timestamp values are Delphi TDateTime numbers. Use DateTimeLib functions like formatdatetime$() and now() to work with them.

Directory Operations

FunctionSignatureDescription
dir_create(path$)dir_create@$Create directory
dir_delete(path$)dir_delete@$Delete empty directory
dir_delete(path$, recursive)dir_delete@$nDelete with recursive option (1=recursive)
dir_exists(path$)dir_exists@$Directory exists? (1/0)
dir_move(src$, dst$)dir_move@$$Move or rename directory
dir_copy(src$, dst$)dir_copy@$$Copy directory recursively
dir_isempty(path$)dir_isempty@$Directory empty? (1/0)
╯ plan9basic
' Create directory
let result = dir_create("myproject")

' Check existence before creating
if dir_exists("backup") = 0 then
    let result = dir_create("backup")
endif

' Delete directory tree (1 = recursive)
let result = dir_delete("temp", 1)

' Copy entire directory
let result = dir_copy("project", "project_backup")
⚠ Warning: dir_delete(path$) without the recursive flag only deletes empty directories. Use dir_delete(path$, 1) to delete a directory and all its contents.

Directory Listing

FunctionSignatureDescription
dir_getfiles$(path$)dir_getfiles$@$All files (CRLF-separated)
dir_getfiles$(path$, pattern$)dir_getfiles$@$$Files matching wildcard pattern
dir_getfiles$(path$, pattern$, recursive)dir_getfiles$@$$nFiles with recursion (1=recurse)
dir_getdirectories$(path$)dir_getdirectories$@$All subdirectories
dir_getdirectories$(path$, pattern$)dir_getdirectories$@$$Directories matching pattern
dir_getdirectories$(path$, pattern$, recursive)dir_getdirectories$@$$nDirectories with recursion
dir_getentries$(path$)dir_getentries$@$All files and directories
dir_getentries$(path$, pattern$)dir_getentries$@$$Entries matching pattern
╯ plan9basic
' List all files
let files$ = dir_getfiles$(documentspath$())
let linecount = count(files$)
for i = 0 to linecount - 1
    println line$(files$, i)
next

' Find .txt files recursively
let txtfiles$ = dir_getfiles$(homepath$(), "*.txt", 1)

' List subdirectories
let subdirs$ = dir_getdirectories$(homepath$())
ⓘ Note: Results are returned as a single string with entries separated by CRLF. Use count() to get the number of lines and line$(str$, idx) to access individual entries (0-based).

Directory Timestamps

FunctionSignatureDescription
dir_getcreationtime(path$)dir_getcreationtime@$Creation time
dir_getlastaccesstime(path$)dir_getlastaccesstime@$Last access time
dir_getlastwritetime(path$)dir_getlastwritetime@$Last modification time
dir_setcreationtime(path$, dt)dir_setcreationtime@$nSet creation time
dir_setlastaccesstime(path$, dt)dir_setlastaccesstime@$nSet last access time
dir_setlastwritetime(path$, dt)dir_setlastwritetime@$nSet modification time

Working Directory

FunctionSignatureDescription
dir_getcurrent$()dir_getcurrent$@Get current working directory
dir_setcurrent(path$)dir_setcurrent@$Set current working directory
dir_getparent$(path$)dir_getparent$@$Get parent directory path
dir_isrelativepath(path$)dir_isrelativepath@$Path is relative? (1/0)
╯ plan9basic
' Save and change directory
let original$ = dir_getcurrent$()
let result = dir_setcurrent(documentspath$())
println "Working in: "; dir_getcurrent$()

' Restore
let result = dir_setcurrent(original$)

' Get parent
let parent$ = dir_getparent$(homepath$())
println "Parent: "; parent$

Path Combining

FunctionSignatureDescription
path_combine$(p1$, p2$)path_combine$@$$Combine two path segments
path_combine$(p1$, p2$, p3$)path_combine$@$$$Combine three path segments
╯ plan9basic
let fullpath$ = path_combine$(homepath$(), "Documents", "report.txt")
println fullpath$
' Windows: C:\Users\John\Documents\report.txt
' Linux:   /home/john/Documents/report.txt

Path Components

FunctionSignatureDescription
path_getdirectoryname$(path$)path_getdirectoryname$@$Directory portion of path
path_getfilename$(path$)path_getfilename$@$Filename with extension
path_getfilenamenoext$(path$)path_getfilenamenoext$@$Filename without extension
path_getextension$(path$)path_getextension$@$Extension (with dot)
path_changeextension$(path$, ext$)path_changeextension$@$$Change file extension
path_hasextension(path$)path_hasextension@$Has extension? (1/0)
path_getpathroot$(path$)path_getpathroot$@$Root portion of path
path_getfullpath$(path$)path_getfullpath$@$Convert to absolute path
╯ plan9basic
let filepath$ = path_combine$(documentspath$(), "report.pdf")

println "Directory: "; path_getdirectoryname$(filepath$)
println "Filename:  "; path_getfilename$(filepath$)
println "Name only: "; path_getfilenamenoext$(filepath$)
println "Extension: "; path_getextension$(filepath$)
println "As backup: "; path_changeextension$(filepath$, ".bak")

' Convert relative to absolute
let rel$ = "data/config.ini"
println "Full: "; path_getfullpath$(rel$)

Path Validation

FunctionSignatureDescription
path_ispathrooted(path$)path_ispathrooted@$Path is absolute? (1/0)
path_isrelativepath(path$)path_isrelativepath@$Path is relative? (1/0)
path_hasvalidpathchars(path$)path_hasvalidpathchars@$Valid path characters? (1/0)
path_hasvalidfilenamechars(name$)path_hasvalidfilenamechars@$Valid filename characters? (1/0)
path_matchespattern(path$, pat$)path_matchespattern@$$Matches wildcard pattern? (1/0)
path_matchespattern(path$, pat$, cs)path_matchespattern@$$nMatch with case sensitivity (1=case-sensitive)
╯ plan9basic
' Validate user input
let userpath$ = "myfile.txt"
if path_hasvalidfilenamechars(userpath$) = 0 then
    println "Invalid filename!"
endif

' Pattern matching
if path_matchespattern("report_2024.pdf", "report_*.pdf") <> 0 then
    println "Matches pattern!"
endif

' Check absolute vs relative
println path_ispathrooted("/home/user")  ' 1
println path_isrelativepath("data/file.txt")  ' 1

Complete Examples

File Manager

╯ file_manager.bas
' Simple file manager
println "=== File Manager ==="

let currentdir$ = dir_getcurrent$()
println "Directory: "; currentdir$
println ""

' List subdirectories
let dirs$ = dir_getdirectories$(currentdir$)
if len(dirs$) > 0 then
    let dircount = count(dirs$)
    for i = 0 to dircount - 1
        let dirname$ = path_getfilename$(line$(dirs$, i))
        println "[DIR]  "; dirname$
    next
endif

' List files with size
let files$ = dir_getfiles$(currentdir$)
if len(files$) > 0 then
    let filecount = count(files$)
    for i = 0 to filecount - 1
        let filepath$ = line$(files$, i)
        let filename$ = path_getfilename$(filepath$)
        let filesize = file_getsize(filepath$)
        println "       "; filename$; " ("; stri$(filesize); " bytes)"
    next
endif

Backup Utility

╯ backup.bas
' Back up all .txt files from Documents to backup folder
println "=== Backup Utility ==="

let srcdir$ = documentspath$()
let bkdir$ = path_combine$(srcdir$, "backup")

if dir_exists(bkdir$) = 0 then
    let result = dir_create(bkdir$)
endif

let files$ = dir_getfiles$(srcdir$, "*.txt")
let copied = 0

if len(files$) > 0 then
    let n = count(files$)
    for i = 0 to n - 1
        let src$ = line$(files$, i)
        let fname$ = path_getfilename$(src$)
        let dst$ = path_combine$(bkdir$, fname$)
        if file_copy(src$, dst$, 1) <> 0 then
            println "OK: "; fname$
            copied = copied + 1
        else
            println "FAIL: "; fname$; " - "; iostrerror$()
        endif
    next
endif

println ""
println "Backed up "; copied; " files"

Log Writer

╯ log_writer.bas
' Persistent log writer
function logwrite(msg$) local logpath$, logline$, result
    logpath$ = path_combine$(documentspath$(), "app.log")
    logline$ = formatdatetime$("yyyy-mm-dd hh:nn:ss", now())
    logline$ = logline$ + " - " + msg$ + chr$(13) + chr$(10)
    result = file_appendalltext(logpath$, logline$)
    return result
endfunction

logwrite("Application started")
logwrite("Processing data...")
logwrite("Done")

' Read log
let log$ = file_readalltext$(path_combine$(documentspath$(), "app.log"))
println log$

Quick Reference

Error Handling (2)

FunctionSignatureDescription
ioerror()ioerror@Last error code (0–10)
iostrerror$()iostrerror$@Error message

File Functions (17)

FunctionSignatureDescription
file_readalltext$(p$) / file_readalltext$(p$, enc$)file_readalltext$@$[$]Read text file
file_readallbytes#(p$)file_readallbytes#@$Read binary file
file_writealltext(p$, c$) / ...(p$, c$, enc$)file_writealltext@$$[$]Write text file
file_appendalltext(p$, c$) / ...(p$, c$, enc$)file_appendalltext@$$[$]Append to text file
file_writeallbytes(p$, s#)file_writeallbytes@$#Write binary file
file_createempty(p$)file_createempty@$Create empty / touch
file_copy(s$, d$) / file_copy(s$, d$, ow)file_copy@$$[n]Copy file
file_move(s$, d$)file_move@$$Move/rename file
file_delete(p$)file_delete@$Delete file
file_exists(p$)file_exists@$File exists? (1/0)
file_getsize(p$)file_getsize@$Size in bytes
file_getcreationtime/getlastaccesstime/getlastwritetime@$Get timestamps
file_setcreationtime/setlastaccesstime/setlastwritetime@$nSet timestamps

Directory Functions (20)

FunctionSignatureDescription
dir_create(p$)dir_create@$Create directory
dir_delete(p$) / dir_delete(p$, rec)dir_delete@$[n]Delete directory
dir_exists(p$)dir_exists@$Exists? (1/0)
dir_move(s$, d$) / dir_copy(s$, d$)dir_move/copy@$$Move/copy
dir_isempty(p$)dir_isempty@$Empty? (1/0)
dir_getfiles$(p$[, pat$[, rec]])dir_getfiles$@$[$[$n]]List files (CRLF-separated)
dir_getdirectories$(p$[, pat$[, rec]])dir_getdirectories$@$[$[$n]]List subdirectories
dir_getentries$(p$[, pat$])dir_getentries$@$[$]List all entries
dir_getcurrent$() / dir_setcurrent(p$)variousWorking directory
dir_getparent$(p$)dir_getparent$@$Parent directory
dir_get/setcreationtime, lastaccesstime, lastwritetimevariousDirectory timestamps (6)

Path Functions (14)

FunctionSignatureDescription
path_combine$(p1$, p2$[, p3$])path_combine$@$$[$]Combine path segments
path_getdirectoryname$(p$)path_getdirectoryname$@$Directory portion
path_getfilename$(p$)path_getfilename$@$Filename with extension
path_getfilenamenoext$(p$)path_getfilenamenoext$@$Filename without extension
path_getextension$(p$)path_getextension$@$Extension (with dot)
path_changeextension$(p$, ext$)path_changeextension$@$$Change extension
path_hasextension(p$)path_hasextension@$Has extension? (1/0)
path_getpathroot$(p$)path_getpathroot$@$Root portion
path_getfullpath$(p$)path_getfullpath$@$Convert to absolute
path_ispathrooted(p$)path_ispathrooted@$Absolute? (1/0)
path_isrelativepath(p$)path_isrelativepath@$Relative? (1/0)
path_hasvalidpathchars(p$)path_hasvalidpathchars@$Valid path chars? (1/0)
path_hasvalidfilenamechars(n$)path_hasvalidfilenamechars@$Valid filename chars? (1/0)
path_matchespattern(p$, pat$[, cs])path_matchespattern@$$[n]Matches wildcard? (1/0)

53 functions across 4 major categories (TFile, TDirectory, TPath, errors).