Skip to content
Reading Input and IO
step 1/7

Reading — step 1 of 7

Learn

~2 min readLists, Recursion, IO

OCaml's stdlib has direct functions for reading and writing — modest but sufficient for daily work. The Stdio library (from Jane Street) is more ergonomic for serious work; for the basics, plain stdlib is enough.

Reading lines

let line = read_line ()              (* reads to newline; strips \n *)
let n = int_of_string line

(* Read N lines: *)
let read_n n =
  let rec loop k acc =
    if k = 0 then List.rev acc
    else loop (k - 1) (read_line () :: acc)
  in
  loop n []

read_line () returns the line as a string (no trailing newline). At end-of-input, raises End_of_file.

Reading all of stdin

let read_all () =
  let rec loop acc =
    try loop (read_line () :: acc)
    with End_of_file -> List.rev acc
  in
  loop []

Loop until exception. Common pattern.

Reading single tokens

(* Scanf for typed input: *)
Scanf.scanf " %s" (fun s -> s)
Scanf.scanf " %d" (fun n -> n)
Scanf.scanf " %d %d" (fun a b -> a + b)

Scanf.scanf is OCaml's typed input. The format string consumes whitespace and parses; the continuation receives the parsed values. Powerful but unusual syntax.

Writing output

print_string "hello"               (* no newline *)
print_endline "hello"               (* with newline *)
print_int 42
print_float 3.14
print_newline ()

(* Formatted: *)
Printf.printf "%d * %d = %d\n" 6 7 42

Standard streams

print_string "to stdout"
prerr_string "to stderr"

Printf.printf "%s\n" "stdout"
Printf.eprintf "%s\n" "stderr"     (* Printf to stderr *)

The e prefix on error variants. prerr_* for error stream functions.

File I/O

(* Read a whole file: *)
let read_file path =
  let ic = open_in path in
  let n = in_channel_length ic in
  let s = really_input_string ic n in
  close_in ic;
  s

(* Write: *)
let write_file path content =
  let oc = open_out path in
  output_string oc content;
  close_out oc

Real code uses Fun.protect or Stdlib.at_exit for cleanup safety. The Jane Street Core library has higher-level wrappers.

Buffer flushing

print_string "no newline yet";
flush stdout                        (* force flush *)

stdout is line-buffered by default. If you don't write a newline, output may not appear immediately. flush stdout forces it.

Common mistakes

  • Forgetting End_of_file — looping read_line () past EOF raises. Catch it.
  • Using read_int () instead of int_of_string (read_line ())read_int exists but it's less robust. Most code reads a line, parses.
  • Forgetting to close files — leaks file descriptors. Use Fun.protect or higher-level helpers.
  • Buffered output not flushing — without a newline, you may not see output. flush or use print_endline.
  • Scanf.scanf quirks — the leading space in " %d" skips whitespace. Without it, leading whitespace causes failures. Many find Scanf surprising; some teams avoid it.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…