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.
| Category | Count | Description |
|---|---|---|
| Error Handling | 2 | ioerror, iostrerror$ |
| File Reading | 3 | file_readalltext$ (2 overloads), file_readallbytes# |
| File Writing | 6 | file_writealltext (2), file_appendalltext (2), file_writeallbytes, file_createempty |
| File Operations | 6 | file_copy (2), file_move, file_delete, file_exists, file_getsize |
| File Timestamps | 6 | get/set creation, access, and write times |
| Directory Ops | 7 | dir_create, dir_delete (2), dir_exists, dir_move, dir_copy, dir_isempty |
| Directory Listing | 8 | dir_getfiles$ (3), dir_getdirectories$ (3), dir_getentries$ (2) |
| Directory Info | 5 | dir_getcurrent$, dir_setcurrent, dir_getparent$, dir_isrelativepath, + timestamps (6) |
| Path Manipulation | 8 | path_combine$ (2), components (6) |
| Path Validation | 6 | path_ispathrooted, isrelativepath, hasvalidpathchars, hasvalidfilenamechars, matchespattern (2) |
Error Handling
| Code | Description |
|---|---|
| 0 | No error |
| 1 | File not found |
| 2 | Directory not found |
| 3 | Access denied |
| 4 | Path too long |
| 5 | Invalid path |
| 6 | I/O error |
| 7 | File already exists |
| 8 | Directory not empty |
| 9 | Invalid argument |
| 10 | Unknown error |
| Function | Signature | Description |
|---|---|---|
ioerror() | ioerror@ | Last error code (0–10) |
iostrerror$() | iostrerror$@ | Descriptive error message |
let content$ = file_readalltext$("missing.txt") if ioerror() <> 0 then println "Error: "; iostrerror$() endif
File Reading
| Function | Signature | Description |
|---|---|---|
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) |
| Encoding | Description |
|---|---|
utf-8 | Default, recommended for most files |
utf-7 | Legacy UTF-7 encoding |
ansi | System default ANSI encoding |
ascii | 7-bit ASCII |
unicode | UTF-16 Little Endian |
utf-16be | UTF-16 Big Endian |
' 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
| Function | Signature | Description |
|---|---|---|
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 |
' 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
| Function | Signature | Description |
|---|---|---|
file_copy(src$, dst$) | file_copy@$$ | Copy file (fails if destination exists) |
file_copy(src$, dst$, overwrite) | file_copy@$$n | Copy 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 |
' 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
| Function | Signature | Description |
|---|---|---|
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@$n | Set creation time |
file_setlastaccesstime(path$, dt) | file_setlastaccesstime@$n | Set last access time |
file_setlastwritetime(path$, dt) | file_setlastwritetime@$n | Set modification time |
' 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
| Function | Signature | Description |
|---|---|---|
dir_create(path$) | dir_create@$ | Create directory |
dir_delete(path$) | dir_delete@$ | Delete empty directory |
dir_delete(path$, recursive) | dir_delete@$n | Delete 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) |
' 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
| Function | Signature | Description |
|---|---|---|
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$@$$n | Files 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$@$$n | Directories with recursion |
dir_getentries$(path$) | dir_getentries$@$ | All files and directories |
dir_getentries$(path$, pattern$) | dir_getentries$@$$ | Entries matching pattern |
' 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
| Function | Signature | Description |
|---|---|---|
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@$n | Set creation time |
dir_setlastaccesstime(path$, dt) | dir_setlastaccesstime@$n | Set last access time |
dir_setlastwritetime(path$, dt) | dir_setlastwritetime@$n | Set modification time |
Working Directory
| Function | Signature | Description |
|---|---|---|
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) |
' 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
| Function | Signature | Description |
|---|---|---|
path_combine$(p1$, p2$) | path_combine$@$$ | Combine two path segments |
path_combine$(p1$, p2$, p3$) | path_combine$@$$$ | Combine three path segments |
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
| Function | Signature | Description |
|---|---|---|
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 |
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
| Function | Signature | Description |
|---|---|---|
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@$$n | Match with case sensitivity (1=case-sensitive) |
' 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
' 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
' 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
' 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)
| Function | Signature | Description |
|---|---|---|
ioerror() | ioerror@ | Last error code (0–10) |
iostrerror$() | iostrerror$@ | Error message |
File Functions (17)
| Function | Signature | Description |
|---|---|---|
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 | @$n | Set timestamps |
Directory Functions (20)
| Function | Signature | Description |
|---|---|---|
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$) | various | Working directory |
dir_getparent$(p$) | dir_getparent$@$ | Parent directory |
dir_get/setcreationtime, lastaccesstime, lastwritetime | various | Directory timestamps (6) |
Path Functions (14)
| Function | Signature | Description |
|---|---|---|
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).