Reading Files in Standard ML

Here’s the translation of the Go code for reading files into Standard ML:

(* Reading and writing files are basic tasks needed for
   many Standard ML programs. First we'll look at some examples of
   reading files. *)

(* Helper function to handle exceptions *)
fun check f x =
    f x
    handle e => (print ("Error: " ^ exnMessage e ^ "\n"); raise e)

(* Perhaps the most basic file reading task is
   slurping a file's entire contents into memory. *)
val dat = check (TextIO.openIn >> TextIO.inputAll) "/tmp/dat"
val _ = print dat

(* You'll often want more control over how and what
   parts of a file are read. For these tasks, start
   by opening a file to obtain a TextIO.instream value. *)
val f = check TextIO.openIn "/tmp/dat"

(* Read some bytes from the beginning of the file.
   Allow up to 5 to be read but also note how many
   actually were read. *)
val b1 = check (TextIO.inputN f) 5
val _ = print (Int.toString (String.size b1) ^ " bytes: " ^ b1 ^ "\n")

(* You can also seek to a known location in the file
   and read from there. *)
val _ = check (TextIO.StreamIO.setPosition (TextIO.getInstream f)) 6
val b2 = check (TextIO.inputN f) 2
val _ = print ("2 bytes @ 6: " ^ b2 ^ "\n")

(* Other methods of seeking are relative to the
   current cursor position, *)
val _ = check (TextIO.StreamIO.skipChars (TextIO.getInstream f)) 4

(* and relative to the end of the file. *)
val _ = check (TextIO.StreamIO.setPosition (TextIO.getInstream f)) 
             (TextIO.StreamIO.endPosition (TextIO.getInstream f) - 10)

(* The TextIO structure provides some functions that may
   be helpful for file reading. For example, reads
   like the ones above can be more robustly
   implemented with inputN. *)
val _ = check (TextIO.StreamIO.setPosition (TextIO.getInstream f)) 6
val b3 = check (TextIO.inputN f) 2
val _ = print ("2 bytes @ 6: " ^ b3 ^ "\n")

(* There is no built-in rewind, but
   setPosition 0 accomplishes this. *)
val _ = check (TextIO.StreamIO.setPosition (TextIO.getInstream f)) 0

(* The TextIO structure implements buffered
   reading that may be useful both for its efficiency
   with many small reads and because of the additional
   reading methods it provides. *)
val b4 = check (TextIO.inputN f) 5
val _ = print ("5 bytes: " ^ b4 ^ "\n")

(* Close the file when you're done *)
val _ = TextIO.closeIn f

To run this program:

$ echo "hello" > /tmp/dat
$ echo "ml" >>   /tmp/dat
$ sml reading-files.sml
hello
ml
5 bytes: hello
2 bytes @ 6: ml
2 bytes @ 6: ml
5 bytes: hello

This Standard ML code demonstrates various file reading operations, including:

  1. Reading an entire file into memory
  2. Opening a file and reading specific portions
  3. Seeking to different positions in the file
  4. Using buffered reading

Note that Standard ML’s file I/O operations are primarily based on the TextIO structure, which provides functions for text-based file operations. The exact equivalents of some Go operations (like Peek) are not available, but similar functionality can be achieved using the provided functions.

Also, error handling in Standard ML is typically done using exceptions, which is why we’ve defined a check function to handle potential errors.

Next, we’ll look at writing files.