(sigil io)
(sigil io) - Input/Output Operations
Provides file and stream I/O for reading and writing data. Includes file ports, character and byte I/O, string ports for building strings efficiently, and basic file system operations.
(import (sigil io))
;; Read entire file
(call-with-input-file "data.txt"
(lambda (port)
(read-all port)))
;; Write to file
(call-with-output-file "output.txt"
(lambda (port)
(write-string "Hello, World!" port)))
;; Build string efficiently
(with-output-to-string
(lambda ()
(display "Result: ")
(display 42)))
; => "Result: 42"Exports
port?procedureCheck if a value is a port.
Returns #t for both input and output ports.
(port? (open-input-file "data.txt")) ; => #t
(port? (open-output-string)) ; => #t
(port? "not a port") ; => #finput-port?procedureCheck if a port is an input port.
(input-port? (open-input-file "data.txt")) ; => #t
(input-port? (open-output-file "out.txt")) ; => #foutput-port?procedureCheck if a port is an output port.
(output-port? (open-output-file "out.txt")) ; => #t
(output-port? (open-input-file "data.txt")) ; => #ftextual-port?procedureCheck if a port is a textual (character) port.
Textual ports handle character I/O (read-char, write-string, etc.).
(textual-port? (open-input-file "data.txt")) ; => #t
(textual-port? (open-binary-input-file "data.bin")) ; => #fbinary-port?procedureCheck if a port is a binary port.
Binary ports handle byte I/O (read-u8, write-bytevector, etc.).
(binary-port? (open-binary-input-file "data.bin")) ; => #t
(binary-port? (open-input-file "data.txt")) ; => #fport-open?procedureCheck if a port is still open.
Returns #t if the port has not been closed.
(let ((port (open-input-file "data.txt")))
(port-open? port) ; => #t
(close-input-port port)
(port-open? port)) ; => #fopen-input-fileprocedureOpen a file for reading text.
Returns an input port. The port should be closed with close-input-port when done, or use call-with-input-file for automatic cleanup.
(let ((port (open-input-file "data.txt")))
(let ((line (read-line port)))
(close-input-port port)
line))open-output-fileprocedureOpen a file for writing text.
Creates the file if it doesn't exist, truncates if it does. The port should be closed with close-output-port when done.
(let ((port (open-output-file "output.txt")))
(write-string "Hello!" port)
(close-output-port port))open-binary-input-fileprocedureOpen a file for reading binary data.
Similar to open-input-file but for binary data. Use with read-u8 and read-bytevector.
open-binary-output-fileprocedureOpen a file for writing binary data.
Similar to open-output-file but for binary data. Use with write-u8 and write-bytevector.
flush-output-portprocedureFlush buffered output to the underlying file.
Forces any buffered data to be written immediately. Useful when you need to ensure data is written before continuing.
(write-string "Progress: 50%" port)
(flush-output-port port) ; ensure it's visible nowport-nameprocedureGet the name associated with a port.
For file ports, returns the filename. For string ports, returns a description like <output-string>.
(port-name (open-input-file "data.txt")) ; => "data.txt"readprocedureRead one S-expression from a port.
Parses and returns the next complete Scheme value. Returns the end-of-file object when the port is exhausted.
;; File contains: (1 2 3) "hello"
(read port) ; => (1 2 3)
(read port) ; => "hello"
(read port) ; => #<eof>
(eof-object? (read port)) ; => #tread-allprocedureRead all S-expressions from a port into a list.
Reads until end-of-file and returns all values as a list. Useful for reading configuration files or data files.
;; File contains: (define x 1) (define y 2)
(call-with-input-file "config.sgl"
(lambda (port) (read-all port)))
; => ((define x 1) (define y 2))read-charprocedureRead a single character from a port.
Returns the next character, or the end-of-file object if the port is exhausted.
(read-char port) ; => #\H
(read-char port) ; => #\epeek-charprocedureLook at the next character without consuming it.
Returns the next character that would be read, but leaves it in the input stream.
(peek-char port) ; => #\H
(peek-char port) ; => #\H (still there)
(read-char port) ; => #\H (now consumed)write-charprocedureWrite a single character to a port.
(write-char #\A port)
(write-char #\newline port)read-lineprocedureRead a line of text from a port.
Returns all characters up to and not including the newline. Returns the end-of-file object if already at end of input.
;; Read all lines from a file
(let loop ((lines '()))
(let ((line (read-line port)))
(if (eof-object? line)
(reverse lines)
(loop (cons line lines)))))read-stringprocedureRead a specific number of characters from a port.
Returns a string with up to n characters. May return fewer if end-of-file is reached.
(read-string 10 port) ; => "Hello, Wor"write-stringprocedureWrite a string to a port.
Outputs the string's characters. Optional start and end indices write a substring.
(write-string "Hello, World!" port)
(write-string "Hello" port 0 4) ; writes "Hell"read-u8procedureRead a single byte from a binary port.
Returns an integer 0-255, or the end-of-file object.
(read-u8 port) ; => 72 (ASCII 'H')write-u8procedureWrite a single byte to a binary port.
The byte must be an integer 0-255.
(write-u8 72 port) ; writes ASCII 'H'read-bytevectorprocedureRead bytes from a port into a bytevector.
With one argument, reads up to n bytes. With a bytevector argument, fills it and returns the count read.
(read-bytevector 1024 port) ; => #u8(72 101 108 ...)write-bytevectorprocedureWrite a bytevector to a port.
Optional start and end indices write a portion.
(write-bytevector #u8(72 101 108 108 111) port) ; writes "Hello"call-with-input-fileprocedureCall a procedure with an input port, ensuring cleanup.
Opens the file, passes the port to proc, closes the port, and returns proc's result. The port is closed even if proc raises an error.
(call-with-input-file "data.txt"
(lambda (port)
(read-line port)))call-with-output-fileprocedureCall a procedure with an output port, ensuring cleanup.
Opens the file, passes the port to proc, closes the port, and returns proc's result.
(call-with-output-file "output.txt"
(lambda (port)
(write-string "Hello!" port)))with-input-from-fileprocedureExecute a thunk with a file as input.
Opens the file and executes the thunk. Currently a simplified version that doesn't rebind current-input-port.
with-output-to-fileprocedureExecute a thunk with output going to a file.
Opens the file and executes the thunk. Currently a simplified version that doesn't rebind current-output-port.
open-output-stringprocedureCreate an output port that writes to a string.
Use get-output-string to retrieve the accumulated output. Much more efficient than building strings with repeated string-append calls.
(let ((port (open-output-string)))
(display "Hello, " port)
(display "World!" port)
(get-output-string port))
; => "Hello, World!"open-input-stringprocedureCreate an input port that reads from a string.
Useful for parsing strings as if they were files.
(let ((port (open-input-string "(1 2 3)")))
(read port))
; => (1 2 3)get-output-stringprocedureGet the accumulated string from a string output port.
Can be called multiple times; each call returns all output written so far.
call-with-output-stringprocedureCall a procedure with a string output port.
The procedure receives the port as an argument and can write to it. Returns the accumulated string.
(call-with-output-string
(lambda (port)
(display "x = " port)
(display 42 port)))
; => "x = 42"with-output-to-stringprocedureExecute a thunk with output going to a string.
Within the thunk, display, write, newline, etc. write to the string port. Returns the accumulated string.
This is the preferred way to build strings from multiple pieces, as it avoids the O(n²) cost of repeated string-append.
(with-output-to-string
(lambda ()
(display "Items: ")
(for-each (lambda (x)
(display x)
(display " "))
'(1 2 3))))
; => "Items: 1 2 3 "call-with-input-stringprocedureCall a procedure with a string input port.
The procedure receives the port and can read from it.
(call-with-input-string "hello world"
(lambda (port)
(read-line port)))
; => "hello world"with-input-from-stringprocedureExecute a thunk with input coming from a string.
Within the thunk, read, read-char, etc. read from the string.
(with-input-from-string "(+ 1 2)"
(lambda () (read)))
; => (+ 1 2)