Four two arm spirals, warped in hyperbolic space.

Chapter 7. Input and Output

This chapter describes input and output operations. All input and output operations are performed through ports. A port is a pointer into a (possibly infinite) stream of characters (typically a file), an opening through which programs may draw characters or objects from the stream or place characters or objects into the stream.

Ports are first-class objects, like any other object in Scheme. Like procedures, ports do not have a printed representation the way strings and numbers do, so they are shown here with the notation #<port>. There are initially two ports in the system, the current input port and the current output port. In an interactive session, these ports usually point to the terminal input and output streams. Several ways to open new ports are provided.

An input port often points to a finite stream, e.g., an input file stored on disk. If one of the input operations (read, read-char, or peek-char) is asked to read from a port that has reached the end of a finite stream, it returns a special eof (end of file) object. The predicate eof-object? may be used to determine if an object returned from read, read-char, or peek-char is an eof object.


Section 7.1. Input Operations

This section describes operations for manipulating input ports.


procedure: (input-port? obj)
returns: #t if obj is an input port, #f otherwise

Ports need not be distinct from other object types.

(input-port? '(a b c)))  unspecified
(input-port? (current-input-port))  #t
(input-port? (open-input-file "infile.ss"))  #t

The last example assumes that "infile.ss" may be opened for input.


procedure: (current-input-port)
returns: the current input port

Most procedures involving input ports may be called with or without an explicit port argument. If called without an explicit port argument, the current input port is used. For example, (read-char) and (read-char (current-input-port)) both return the next character from the current input port.


procedure: (open-input-file filename)
returns: a new input port

filename must be a string. open-input-file creates a new input port for the file named by filename. An error is signaled if the file does not exist or cannot be opened for input. See the example given for close-input-port.


procedure: (close-input-port input-port)
returns: unspecified

close-input-port closes an input port. Once an input port has been closed, no more input operations may be performed on that port. Because the operating system may place limits on the number of ports open at one time or restrict access to an open port, it is a good practice to close any port that will no longer be used for input or output. Some Scheme implementations close ports automatically after they become inaccessible to the program or when the Scheme program exits, but it is best to close ports explicitly whenever possible.

It is not an error to close a port that has already been closed; doing so has no effect.

The following shows the use of open-input-file and close-input-port in an expression that gathers a list of objects from the file "myfile.ss". It is functionally equivalent to the example given for call-with-input-file below.

(let ((p (open-input-file "myfile.ss")))
  (let f ((x (read p)))
    (if (eof-object? x)
        (begin
          (close-input-port p)
          '())
        (cons x (f (read p))))))


procedure: (call-with-input-file filename proc)
returns: the result of invoking proc

filename must be a string. proc must be a procedure of one argument.

call-with-input-file creates a new input port for the file named by filename and passes this port to proc. An error is signaled if the file does not exist or cannot be opened for input. If proc returns, call-with-input-file closes the input port and returns the value returned by proc.

call-with-input-file does not automatically close the input port if a continuation created outside of proc is invoked, since it is possible that another continuation created inside of proc will be invoked at a later time, returning control to proc. If proc does not return, an implementation is free to close the input port only if it can prove that the input port is no longer accessible. As shown in Section 5.6, dynamic-wind may be used to ensure that the port is closed if a continuation created outside of proc is invoked.

call-with-input-file might be defined as follows.

(define call-with-input-file
  (lambda (filename proc)
    (let ((p (open-input-file filename)))
      (let ((v (proc p)))
        (close-input-port p)
        v))))

The following example shows the use of call-with-input-file in an expression that gathers a list of objects from the file "myfile.ss". It is functionally equivalent to the example given for close-input-port above.

(call-with-input-file "myfile.ss"
  (lambda (p)
    (let f ((x (read p)))
      (if (eof-object? x)
          '()
          (cons x (f (read p)))))))


procedure: (with-input-from-file filename thunk)
returns: the value returned by thunk

filename must be a string.

with-input-from-file temporarily changes the current input port to be the result of opening the file named by filename for input during the application of thunk. If thunk returns, the port is closed and the current input port is restored to its old value.

The behavior of with-input-from-file is unspecified if a continuation created outside of thunk is invoked before thunk returns. An implementation may close the port and restore the current input port to its old value---but it may not.

with-input-from-file is in the Revised4 Report but not the ANSI/IEEE standard.


procedure: (read)
procedure: (read input-port)
returns: the next object from input-port

If input-port is not supplied, it defaults to the current input port. If input-port is at end of file, an eof object is returned. See the examples given for close-input-port and call-with-input-file.


procedure: (read-char)
procedure: (read-char input-port)
returns: the next character from input-port

If input-port is not supplied, it defaults to the current input port. If input-port is at end of file, an eof object is returned. See the examples given for peek-char and write-char.


procedure: (peek-char)
procedure: (peek-char input-port)
returns: the next character from input-port

If input-port is not supplied, it defaults to the current input port. If input-port is at end of file, an eof object is returned.

In contrast to read-char, peek-char does not consume the character it reads from input-port; a subsequent call to peek-char or read-char returns the same character.

peek-char is provided for applications requiring one character of lookahead. The procedure read-word defined below returns the next word from an input port as a string, where a word is defined to be a sequence of alphabetic characters. Since read-word does not know until it sees one character beyond the word that it has read the entire word, it uses peek-char to determine the next character and read-char to consume the character.

(define read-word
  (lambda (p)
    (list->string
      (let f ()
        (let ((c (peek-char p)))
          (cond
            ((eof-object? c) '())
            ((char-alphabetic? c)
             (read-char p)
             (cons c (f)))
            (else '())))))))


procedure: (eof-object? obj)
returns: #t if obj is an eof object, #f otherwise

An end-of-file object is returned by read, read-char, or peek-char when an input port has reached the end of input. Although end-of-file objects need not be distinct from other object types, they are unique in the sense that they cannot be confused with objects that may be returned by read, read-char, or peek-char when the input port has not reached the end of input. For example, if (eof-object? x) is #t, (eq? x #\a) must be false but (char? x) may be true or false.


procedure: (char-ready?)
procedure: (char-ready? input-port)
returns: #t if a character is available on input-port, #f otherwise

If input-port is not supplied, it defaults to the current input port.

char-ready? allows a program to look for character input on an interactive port without hanging. If char-ready? returns #t, the next peek-char or read-char operation on input-port will not be delayed. If input-port is at end of file, char-ready? returns #t. char-ready? is in the Revised4 Report but not the ANSI/IEEE standard.


Section 7.2. Output Operations

This section describes operations for manipulating output ports.


procedure: (output-port? obj)
returns: #t if obj is an output port, #f otherwise

Ports need not be distinct from other object types.

(output-port? '(a b c)))  unspecified
(output-port? (current-output-port))  #t
(output-port? (open-output-file "outfile.ss"))  #t

The last example assumes that "outfile.ss" may be opened for output.


procedure: (current-output-port)
returns: the current output port

Most procedures involving output ports may be called with or without an explicit port argument. If called without an explicit port argument, the current output port is used. For example, (write obj) and (write obj (current-output-port)) both write to the current output port.


procedure: (open-output-file filename)
returns: a new output port

filename must be a string. open-output-file creates a new output port for the file named by filename. An error is signaled if the file cannot be opened for output. See the example given for close-output-port.


procedure: (close-output-port output-port)
returns: unspecified

close-output-port closes an output port. Once an output port has been closed, no more output operations may be performed on that port. Because the operating system may place limits on the number of ports open at one time or restrict access to an open port, it is a good practice to close any port that will no longer be used for input or output. Also, because the system may buffer output for efficiency, some of the output may not appear on the file until the file has been closed. Some Scheme implementations close ports automatically after they become inaccessible to the program or when the Scheme program exits, but it is best to close ports explicitly whenever possible.

It is not an error to close a port that has already been closed; doing so has no effect.

The following shows the use of open-output-file and close-output-port to write a list of objects (the value of list-to-be-printed), separated by newlines, to the file "myfile.ss". It is functionally equivalent to the example given for call-with-output-file below.

(let ((p (open-output-file "myfile.ss")))
  (let f ((ls list-to-be-printed))
    (if (not (null? ls))
        (begin
          (write (car ls) p)
          (newline p)
          (f (cdr ls)))))
  (close-output-port p))


procedure: (call-with-output-file filename proc)
returns: the result of invoking proc

filename must be a string. proc must be a procedure of one argument.

call-with-output-file creates a new output port for the file named by filename and passes this port to proc. An error is signaled if the file cannot be opened for output. If proc returns, call-with-output-file closes the output port and returns the value returned by proc.

call-with-output-file does not automatically close the output port if a continuation created outside of proc is invoked, since it is possible that another continuation created inside of proc will be invoked at a later time, returning control to proc. If proc does not return, an implementation is free to close the output port only if it can prove that the output port is no longer accessible. As shown in Section 5.6, dynamic-wind may be used to ensure that the port is closed if a continuation created outside of proc is invoked.

call-with-output-file might be defined as follows.

(define call-with-output-file
  (lambda (filename proc)
    (let ((p (open-output-file filename)))
      (let ((v (proc p)))
        (close-output-port p)
        v))))

The following shows the use of call-with-output-file to write a list of objects (the value of list-to-be-printed), separated by newlines, to the file "myfile.ss". It is functionally equivalent to the example given for close-output-port above.

(call-with-output-file "myfile.ss"
  (lambda (p)
    (let f ((ls list-to-be-printed))
      (if (not (null? ls))
          (begin
            (write (car ls) p)
            (newline p)
            (f (cdr ls)))))))


procedure: (with-output-to-file filename thunk)
returns: the value returned by thunk

filename must be a string.

with-output-to-file temporarily rebinds the current output port to be the result of opening the file named by filename for output during the application of thunk. If thunk returns, the port is closed and the current output port is restored to its old value.

The behavior of with-output-to-file is unspecified if a continuation created outside of thunk is invoked before thunk returns. An implementation may close the port and restore the current output port to its old value---but it may not.

with-output-to-file is in the Revised4 Report but not the ANSI/IEEE standard.


procedure: (write obj)
procedure: (write obj output-port)
returns: unspecified

If output-port is not supplied, it defaults to the current output port.

write prints obj to output-port in such a way that it can later be read by the procedure read, unless it contains unprintable objects such as procedures, ports, or symbols containing nonstandard characters. Strings are printed within quote marks, using slashes where necessary, and characters are printed with the #\ notation. See Section 9.5 for an implementation of write and display.


procedure: (display obj)
procedure: (display obj output-port)
returns: unspecified

If output-port is not supplied, it defaults to the current output port.

display is similar to write but prints strings and characters found within obj directly. Strings are printed without quotation marks or slashes, and characters are printed without the #\ notation. For example, both (display "(a b c)") and (display '("a b" c)) would print (a b c). Because of this, display should not be used to print objects that are intended to be read with read. display is useful primarily for printing messages, with obj most often being a string. See Section 9.5 for an implementation of write and display.


procedure: (write-char char)
procedure: (write-char char output-port)
returns: unspecified

If output-port is not supplied, it defaults to the current output port. write-char writes the single character char to output-port, without the #\ notation. The following example copies the contents of one file to another, one character at a time.

(call-with-input-file "infile"
  (lambda (ip)
    (call-with-output-file "outfile"
      (lambda (op)
        (do ((c (read-char ip) (read-char ip)))
            ((eof-object? c))
            (write-char c op))))))


procedure: (newline)
procedure: (newline output-port)
returns: unspecified

If output-port is not supplied, it defaults to the current output port. newline sends a newline character to output-port. It may be defined as follows:

(define newline
  (lambda args
    (apply write-char #\newline args)))


Section 7.3. Loading Programs


procedure: (load filename)
returns: unspecified

filename must be a string. load reads and evaluates in sequence each expression in the file specified by filename. load is in the Revised4 Report but not the ANSI/IEEE standard.


Section 7.4. Transcript Files

A transcript file is a record of an interactive session. It is also useful as a "quick-and-dirty" alternative to opening an output file and using explicit output operations.

transcript-on and transcript-off are in the Revised4 Report but not the ANSI/IEEE standard.


procedure: (transcript-on filename)
returns: unspecified

filename must be a string.

transcript-on opens the file named by filename for output, and it copies to this file all input from the current input port and all output to the current output port. An error is signaled if the file cannot be opened for output.


procedure: (transcript-off)
returns: unspecified

transcript-off ends transcription and closes the transcript file.


R. Kent Dybvig
The Scheme Programming Language, Second Edition
© 1996. Electronically reproduced by permission of Prentice Hall, Upper Saddle River, New Jersey.
http://www.scheme.com
Illustrations © 1997 Jean-Pierre Hébert
to order this book
about this book