CS 312 Recitation 9:
SML Input/Output

Note: Much of this information is borrowed from the Basis Library. Please see the Basis Library for full specifications.

To be able to read from and write to files we need functions that will enable us to open and close files and either input information from the file or output to the file. Files are being manipulated using file handles, called streams. For now think of streams as sequences of elements (for files, sequences of bytes or characters). The built-in IMPERATIVE_IO signature defines operations to open files, read/write files, and close files.  The signature also defines two types called instream and outstream. An instream (input streams) is a type that allows you to input or read the elements of the stream one at a time and an outstream (output streams) allows you to output or write elements to a stream one at a time.

signature IMPERATIVE_IO = sig 
  type vector
  type elem
  type instream
  type outstream
val input1 : instream -> elem option val inputN : (instream * int) -> vector val inputAll : instream -> vector val canInput : (instream * int) -> int option val lookahead : instream -> elem option val closeIn : instream -> unit
val output : (outstream * vector) -> unit val output1 : (outstream * elem) -> unit val flushOut : outstream -> unit val closeOut : outstream -> unit ...
end
input1, inputN and inputAll functions are used to read one, N, or all elemens of a instream; output and output1 functions are used to write all or one element to an outstream. Notice that these functions have an imperative behavior (as indicated by the name of the signature): they do not return a new instream or outstream (the return type is unit). Instead, the current position in the stream is "advanced" one step ahead as a side-effect.

closeIn and closeOut are used to close an instream and outstream, respectively. Make sure you close streams after you are done reading from or writing to them. The output streams contain buffers that might not be flushed out until you close the files (or perform an explicit flushOut operation).

type vector
type elem
These are the abstract types of stream elements and vectors of elements. For text files like those used in TextIO, these are Char.char and String.string, while for binary files like those used in BinIO, these are Word8.word and Word8Vector.vector.

The IMPERATIVE_IO signature provide the common part for two other signatures: BIN_IO (for binary file manipulations) and TEXT_IO (for text file manipulations). These signatures are implemented by structures BinIO and TextIO, respectively. Hence, BinIO and TextIO support all of the above functions, plus the ones discussed below.

The Binary IO Structure: BinIO

The BinIO structure provides support for manipulating binary files. The structure BinIO implements the BIN_IO signature, which extends the IMPERATIVE_IO interface with functions for opening files:

  include IMPERATIVE_IO
  val openIn : string -> instream 
  val openOut : string -> outstream 
  val openAppend : string -> outstream 

openIn name
openOut name

Open the file named name for binary input (reading) and output (writing), respectively. If name is a relative pathname, the file opened depends on the current working directory. On openOut, the file is created if it does not already exist and truncated to length zero otherwise. Raises Io if a stream cannot be opened on the given file or, in the case of openIn, the file name does not exist.

For binary files the elem and vector types are defined using the Word8 structure, as follows:

type vector = Word8Vector.vector 
type elem = Word8.word 
The type Word8.word essentially represents unsigned 8-bit integers. The Word8 structure implements the WORD signature, and  provides arithmetic and logical operations and conversion operations (e.g. bitwise and, bitwise or, bitwise shifts) for this type. They are meant to give efficient access to the primitive machine word types of the underlying hardware. (The structures such as Int8 or Int32 implement the INTEGER signature and model signed integers.)
 

Text IO Structure: TextIO

The TextIO structure provides support for manipulating text files. The structure also defines functions for opening text files. In addition, it defines the standard in, standard out, and standard error streams, and provides some functions specific to text files (such as reading a line from an input stream). The structure TextIO implements the TEXT_IO signature, which includes the following:

  include IMPERATIVE_IO
  val inputLine : instream -> string
  val openIn : string -> instream
  val openOut : string -> outstream
  val stdIn : instream
  val stdOut : outstream
  val stdErr : outstream
  val print : string -> unit
  ...
openIn name
openOut name

Open the file named name for text input (reading) and output (writing), respectively. Their behavior is similar to the corresponding functions for binary files.

inputLine strm
Reads one line from strm and return it. If strm is not at end of file, the result ends with a newline character. If it is the last line of the file and the file ends without a trailing newline, stick the newline on anyway. If at end of file, return the empty string. Raises Size if the length of the line exceeds the length of the longest string.

val stdIn
val stdOut
val stdErr
These correspond to the standard input, output and error streams, respectively.

print s
prints the string s to the standard output stream and flushes the stream. This is equivalent to: (output (stdOut, s); flushOut stdOut)

For binary file the elem and vector types are:

type vector = String.string
type elem = char 

 

Example

This is a simple example using TextIO that copies the contents of from one text file, infile, to another, outfile:

fun copyTextFile(infile: string, outfile: string) =
  let
    val ins = TextIO.openIn infile
    val outs = TextIO.openOut outfile
    fun helper(copt: char option) =
      case copt of
           NONE => (TextIO.closeIn ins; TextIO.closeOut outs)
         | SOME(c) => (TextIO.output1(outs,c); helper(TextIO.input1 ins))
  in
    helper(TextIO.input1 ins)
  end