How do I read in lines from a text file in OCaml?

后端 未结 7 934
心在旅途
心在旅途 2020-12-31 02:18

This is what I have so far. Isn\'t this all that you need? I keep getting the error \"Error: Unbound module Std\"

let r file =
    let chan = open_in file in         


        
相关标签:
7条回答
  • 2020-12-31 02:56

    Here's a recursive solution using Scanf:

    let read_all_lines file_name =
      let in_channel = open_in file_name in
      let rec read_recursive lines =
        try
          Scanf.fscanf in_channel "%[^\r\n]\n" (fun x -> read_recursive (x :: lines))
        with
          End_of_file ->
            lines in
      let lines = read_recursive [] in
      let _ = close_in_noerr in_channel in
      List.rev (lines);;
    

    Usage:

    let all_lines = read_all_lines "input.txt";;
    

    However, I'd prefer to stream line-by-line:

    let make_reader file_name =
      let in_channel = open_in file_name in
      let closed = ref false in
      let read_next_line = fun () ->
        if !closed then
          None
        else
          try
            Some (Scanf.fscanf in_channel "%[^\r\n]\n" (fun x -> x))
          with
            End_of_file ->
              let _ = close_in_noerr in_channel in
              let _ = closed := true in
              None in
      read_next_line;;
    

    Usage:

    let read_next = make_reader "input.txt";;
    let next_line = read_next ();;
    

    And may be a bit of icing:

    type reader = {read_next : unit -> string option};;
    
    let make_reader file_name =
      let in_channel = open_in file_name in
      let closed = ref false in
      let read_next_line = fun () ->
        if !closed then
          None
        else
          try
            Some (Scanf.fscanf in_channel "%[^\r\n]\n" (fun x -> x))
          with
            End_of_file ->
              let _ = close_in_noerr in_channel in
              let _ = closed := true in
              None in
      {read_next = read_next_line};;
    

    Usage:

    let r = make_reader "input.txt";;
    let next_line = r.read_next ();;
    

    Hope this helps!

    0 讨论(0)
  • 2020-12-31 02:57

    If you have the OCaml Core library installed, then it is as simple as:

    open Core.Std
    let r file = In_channel.read_lines file
    

    If you have corebuild installed, then you can just compile your code with it:

    corebuild filename.byte
    

    if your code resides in a file named filename.ml.

    If you don't have the OCaml Core, or do not want to install it, or some other standard library implementation, then, of course, you can implement it using a vanilla OCaml's standard library. There is a function input_line, defined in the Pervasives module, that is automatically opened in all OCaml programs (i.e. all its definitions are accessible without further clarification with a module name). This function accepts a value of type in_channel and returns a line, that was read from the channel. Using this function you can implement the required function:

    let read_lines name : string list =
      let ic = open_in name in
      let try_read () =
        try Some (input_line ic) with End_of_file -> None in
      let rec loop acc = match try_read () with
        | Some s -> loop (s :: acc)
        | None -> close_in ic; List.rev acc in
      loop []
    

    This implementation uses recursion, and is much more natural to OCaml programming.

    0 讨论(0)
  • 2020-12-31 03:02

    Another style to read lines from a file using Scanf "string indiciation" and zero-width character. It is like traditional imperative style.

    open Scanf 
    open Printf
    
    (* little helper functions *)
    let id x = x 
    let const x = fun _ -> x
    let read_line file = fscanf file "%s@\n" id 
    let is_eof file = try fscanf file "%0c" (const false) with End_of_file -> true
    
    let _ = 
      let file = open_in "/path/to/file" in 
    
      while not (is_eof file) do 
        let s = read_line file in
        (* do something with s *) 
        printf "%s\n" s 
      done;
    
      close_in file
    

    NOTE:

    1. read_line ignore one trailing \n, so if the last character of your file is \n, it may seems like you have missed the last empty line.
    2. when using of Scanf, due to bufferization, do not mix other low level reading on the same channel, otherwise it will result in strange behaviour.
    0 讨论(0)
  • 2020-12-31 03:03

    This reads the file's lines and prints each of them:

    open Core.Std
    
    let handle_line line =
      printf "Your line: %s \n" line
    
    let () =
      let file_to_read = "./file_to_read.txt" in
        let lines = In_channel.read_lines file_to_read in
          List.iter ~f: handle_line lines
    
    0 讨论(0)
  • 2020-12-31 03:05

    An imperative solution using just the standard library:

    let read_file filename = 
    let lines = ref [] in
    let chan = open_in filename in
    try
      while true; do
        lines := input_line chan :: !lines
      done; !lines
    with End_of_file ->
      close_in chan;
      List.rev !lines ;;
    

    If you have the Batteries-included library you could read a file into an Enum.t and iterate over it as follows:

    let filelines = File.lines_of filename in
    Enum.iter ( fun line -> (*Do something with line here*) ) filelines
    
    0 讨论(0)
  • 2020-12-31 03:05

    Std.input_list apparently requires Extlib, which you should install on your system (libextlib-ocaml and libextlib-ocaml-dev on Debian systems).

    0 讨论(0)
提交回复
热议问题