254 lines
7.6 KiB
Racket
254 lines
7.6 KiB
Racket
#lang scribble/doc
|
|
@require[scribble/manual]
|
|
@require[scribble/struct]
|
|
@require[scribble/eval]
|
|
@require[mzlib/process]
|
|
@require["guide-utils.ss"]
|
|
|
|
@define[(twocolumn a b)
|
|
(make-table #f
|
|
(list (list (make-flow (list a))
|
|
(make-flow (list (make-paragraph (list (hspace 1)))))
|
|
(make-flow (list b)))))]
|
|
@interaction-eval[(print-hash-table #t)]
|
|
|
|
@title[#:tag "i/o" #:style 'toc]{Input and Output}
|
|
|
|
A Scheme @defterm{port} represents an input or output stream, such as
|
|
a file, a terminal, a TCP connection, or an in-memory string. More
|
|
specifically, an @defterm{input port} represents a stream from which a
|
|
program can read data, and an @defterm{output port} represents a
|
|
stream for writing data.
|
|
|
|
@local-table-of-contents[]
|
|
|
|
@;------------------------------------------------------------------------
|
|
@section{Varieties of Ports}
|
|
|
|
Various functions create various kinds of ports. Here are a few
|
|
examples:
|
|
|
|
@itemize{
|
|
|
|
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
@item{@bold{Files:} The @scheme[open-output-file] function opens a
|
|
file for writing, and @scheme[open-input-file] opens a file for
|
|
reading.
|
|
|
|
@interaction-eval[(define old-dir (current-directory))]
|
|
@interaction-eval[(current-directory (find-system-path 'temp-dir))]
|
|
@interaction-eval[(when (file-exists? "data") (delete-file "data"))]
|
|
|
|
@examples[
|
|
(define out (open-output-file "data"))
|
|
(display "hello" out)
|
|
(close-output-port out)
|
|
(define in (open-input-file "data"))
|
|
(read-line in)
|
|
(close-input-port in)
|
|
]
|
|
|
|
@interaction-eval[(delete-file "data")]
|
|
|
|
Instead of having to match @scheme[open-input-file] and
|
|
@scheme[open-output-file] calls, most Scheme programmers will instead
|
|
use @scheme[call-with-output-file], which takes a function to call
|
|
with the output port; when the function returns, the port is closed.
|
|
|
|
@examples[
|
|
(call-with-output-file "data"
|
|
(lambda (out)
|
|
(display "hello" out)))
|
|
(call-with-input-file "data"
|
|
(lambda (in)
|
|
(read-line in)))
|
|
]
|
|
|
|
@interaction-eval[(delete-file "data")]
|
|
@interaction-eval[(current-directory old-dir)]}
|
|
|
|
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
@item{@bold{Strings:} The @scheme[open-output-string] function creates
|
|
a port that accumulates data into a string, and @scheme[get-output-string]
|
|
extracts the accumulated string. The @scheme[open-input-string] function
|
|
creates a port to read from a string.
|
|
|
|
@examples[
|
|
(define p (open-output-string))
|
|
(display "hello" p)
|
|
(get-output-string p)
|
|
(read-line (open-input-string "goodbye\nfarewell"))
|
|
]}
|
|
|
|
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
@item{@bold{TCP Connections:} The @scheme[tcp-connect] function
|
|
creates both an input port and an output port for the client side of
|
|
a TCP communication. The @scheme[tcp-listen] function creates a
|
|
server, which accepts connections via @scheme[tcp-accept].
|
|
|
|
@examples[
|
|
(eval:alts (define server (tcp-listen 12345)) (void))
|
|
(eval:alts (define-values (c-in c-out) (tcp-connect "localhost" 12345)) (void))
|
|
(eval:alts (define-values (s-in s-out) (tcp-accept server))
|
|
(begin (define-values (s-in c-out) (make-pipe))
|
|
(define-values (c-in s-out) (make-pipe))))
|
|
(display "hello\n" c-out)
|
|
(read-line s-in)
|
|
(close-output-port c-out)
|
|
(read-line s-in)
|
|
]}
|
|
|
|
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
@item{@bold{Process Pipes:} The @scheme[process] function runs a new
|
|
process at the OS level and returns ports that correspond to the
|
|
subprocess's stdin, stdout, and stderr. (The first three arguments
|
|
can be certain kinds of existing ports to connect directly to the
|
|
subprocess, instead of creating new ports.)
|
|
|
|
@examples[
|
|
(eval:alts
|
|
(define-values (p stdout stdin stderr)
|
|
(subprocess #f #f #f "/usr/bin/wc" "-w"))
|
|
(define-values (p stdout stdin stderr)
|
|
(values #f (open-input-string " 3") (open-output-string) (open-input-string ""))))
|
|
(display "a b c\n" stdin)
|
|
(close-output-port stdin)
|
|
(read-line stdout)
|
|
(close-input-port stdout)
|
|
(close-input-port stderr)
|
|
]}
|
|
|
|
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
@item{@bold{Internal Pipes:} The @scheme[make-pipe] function returns
|
|
two ports that are ends of a pipe. This kind of pipe is internal to
|
|
Scheme, and not related to OS-level pipes for communicating between
|
|
different processes.
|
|
|
|
@examples[
|
|
(define-values (in out) (make-pipe))
|
|
(display "garbage" out)
|
|
(close-output-port out)
|
|
(read-line in)
|
|
]}
|
|
|
|
}
|
|
|
|
@;------------------------------------------------------------------------
|
|
@section{Default Ports}
|
|
|
|
For most simple I/O functions, the target port is an optional
|
|
argument, and the default is the @defterm{current input port} or
|
|
@defterm{current output port}. Furthermore, error messages are written
|
|
to the @defterm{current error port}, which is an output port. The
|
|
@scheme[current-input-port], @scheme[current-output-port], and
|
|
@scheme[current-error-port] functions return the corresponding current
|
|
ports.
|
|
|
|
@examples[
|
|
(display "Hi")
|
|
(code:line (display "Hi" (current-output-port)) (code:comment #, @t{the same}))
|
|
]
|
|
|
|
If you start the @exec{mzscheme} program in a terminal, then the
|
|
current input, output, and error ports are all connected to the
|
|
terminal. More generally, they are connected to the OS-level stdin,
|
|
stdout, and stderr. In this guide, the examples show output written to
|
|
stdout in purple, and output written to stderr in red italics.
|
|
|
|
@defexamples[
|
|
(define (swing-hammer)
|
|
(display "Ouch!" (current-error-port)))
|
|
(swing-hammer)
|
|
]
|
|
|
|
The current-port functions are actually @tech{parameters}, which means
|
|
that their values can be set with @scheme[parameterize].
|
|
|
|
@moreguide["parameters"]{parameters}
|
|
|
|
@examples[
|
|
(let ([s (open-output-string)])
|
|
(parameterize ([current-error-port s])
|
|
(swing-hammer)
|
|
(swing-hammer)
|
|
(swing-hammer))
|
|
(get-output-string s))
|
|
]
|
|
|
|
@; ----------------------------------------------------------------------
|
|
@section{Reading and Writing Scheme Data}
|
|
|
|
As noted throughout @secref["datatypes"], Scheme provides two
|
|
ways to print an instance of a built-in value:
|
|
|
|
@itemize{
|
|
|
|
@item{ @scheme[write], which prints a value in the same way that is it
|
|
printed for a @tech{REPL} result; and }
|
|
|
|
@item{@scheme[display], which tends to reduce a value to just its
|
|
character or byte content---at least for those datatypes that
|
|
are primarily about characters or bytes, otherwise it falls
|
|
back to the same output as @scheme[write].}
|
|
|
|
}
|
|
|
|
@twocolumn[
|
|
|
|
@interaction[
|
|
(write 1/2)
|
|
(write #\x)
|
|
(write "hello")
|
|
(write #"goodbye")
|
|
(write '|dollar sign|)
|
|
(write '("alphabet" soup))
|
|
(write write)
|
|
]
|
|
|
|
@interaction[
|
|
(display 1/2)
|
|
(display #\x)
|
|
(display "hello")
|
|
(display #"goodbye")
|
|
(display '|dollar sign|)
|
|
(display '("alphabet" soup))
|
|
(display write)
|
|
]
|
|
|
|
]
|
|
|
|
The @scheme[printf] function supports simple formatting of data and
|
|
text. In the format string supplied to @scheme[printf], @litchar{~a}
|
|
@scheme[display]s the next argument, while @litchar{~s}
|
|
@scheme[write]s the next argument.
|
|
|
|
@defexamples[
|
|
(define (deliver who what)
|
|
(printf "Value for ~a: ~s" who what))
|
|
(deliver "John" "string")
|
|
]
|
|
|
|
An advantage of @scheme[write] is that many forms of data can be
|
|
read back in using @scheme[read].
|
|
|
|
@examples[
|
|
(define-values (in out) (make-pipe))
|
|
(write "hello" out)
|
|
(read in)
|
|
(write '("alphabet" soup) out)
|
|
(read in)
|
|
(write #hash((a . "apple") (b . "banana")) out)
|
|
(read in)
|
|
]
|
|
|
|
@; ----------------------------------------------------------------------
|
|
@subsection{Serialization}
|
|
|
|
|
|
@; ----------------------------------------------------------------------
|
|
@section{Bytes versus Characters}
|
|
|