Reading Files in OCaml

Our first example demonstrates reading files in OCaml. Reading and writing files are basic tasks needed for many OCaml programs. Let’s look at some examples of reading files.

open Core

(* Reading files requires checking most calls for errors.
   This helper will streamline our error checks below. *)
let check_exn result =
  match result with
  | Ok x -> x
  | Error e -> raise (Unix.Unix_error (e, "", ""))

let () =
  (* Perhaps the most basic file reading task is
     slurping a file's entire contents into memory. *)
  let dat = In_channel.read_all "/tmp/dat" in
  printf "%s" 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 an In_channel value. *)
  let ic = In_channel.create "/tmp/dat" in

  (* Read some bytes from the beginning of the file.
     Allow up to 5 to be read but also note how many
     actually were read. *)
  let b1 = Bytes.create 5 in
  let n1 = check_exn (In_channel.input ic ~buf:b1 ~pos:0 ~len:5) in
  printf "%d bytes: %s\n" n1 (Bytes.sub_string b1 0 n1);

  (* You can also seek to a known location in the file
     and read from there. *)
  check_exn (In_channel.seek ic 6L);
  let b2 = Bytes.create 2 in
  let n2 = check_exn (In_channel.input ic ~buf:b2 ~pos:0 ~len:2) in
  printf "%d bytes @ %d: %s\n" n2 6 (Bytes.to_string b2);

  (* Other methods of seeking are relative to the
     current cursor position, *)
  check_exn (In_channel.seek ic (Int64.of_int 4));

  (* and relative to the end of the file. *)
  check_exn (In_channel.seek ic (Int64.of_int (-10)));

  (* The Core library provides some functions that may
     be helpful for file reading. For example, reads
     like the ones above can be more robustly
     implemented with In_channel.really_input. *)
  check_exn (In_channel.seek ic 6L);
  let b3 = Bytes.create 2 in
  check_exn (In_channel.really_input ic b3 0 2);
  printf "%d bytes @ %d: %s\n" 2 6 (Bytes.to_string b3);

  (* There is no built-in rewind, but
     seek to 0 accomplishes this. *)
  check_exn (In_channel.seek ic 0L);

  (* The Core library also implements a buffered
     reader that may be useful both for its efficiency
     with many small reads and because of the additional
     reading methods it provides. *)
  let reader = Stdio.In_channel.create "/tmp/dat" in
  let line = Stdio.In_channel.input_line_exn reader in
  printf "First line: %s\n" line;

  (* Close the file when you're done (usually this would
     be scheduled immediately after opening with
     `finally`). *)
  In_channel.close ic;
  Stdio.In_channel.close reader

To run this program:

$ echo "hello" > /tmp/dat
$ echo "ocaml" >> /tmp/dat
$ ocaml reading_files.ml
hello
ocaml
5 bytes: hello
2 bytes @ 6: oc
2 bytes @ 6: oc
First line: hello

This example demonstrates various ways to read files in OCaml, including reading entire files, seeking to specific positions, and using buffered readers. It also shows how to handle potential exceptions when working with files.

Next, we’ll look at writing files.