如何从OCaml中的文本文件中读取行?

时间:2011-04-25 03:37:48

标签: ocaml

这是我到目前为止所拥有的。这不就是你需要的吗?我一直收到错误“错误:未绑定的模块标准”

let r file =
    let chan = open_in file in
    Std.input_list (chan)

8 个答案:

答案 0 :(得分:22)

如果您没有安装Extlib(显然您没有根据上面的错误消息),那么通常它就是这样做的:

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 ;;

如果你有Extlib:

let read_file filename =
  let chan = open_in filename in
  Std.input_list chan

......这几乎就是你所拥有的。

如果你有Batteries-included库,你可以将文件读入Enum.t并按如下方式迭代它:

let filelines = File.lines_of filename in
Enum.iter ( fun line -> (*Do something with line here*) ) filelines

答案 1 :(得分:16)

如果您安装了OCaml Core库,那么它就像:

一样简单
open Core.Std
let r file = In_channel.read_lines file

如果您安装了corebuild,那么您可以使用它编译代码:

corebuild filename.byte

如果您的代码位于名为filename.ml的文件中。

如果您没有OCaml Core,或者不想安装它,或者其他一些标准库实现,那么,当然,您可以使用vanilla OCaml的标准库来实现它。在input_line模块中定义了一个函数Pervasives,它在所有OCaml程序中自动打开(即所有定义都可以访问,无需进一步说明模块名称)。此函数接受类型in_channel的值,并返回从通道读取的行。使用此功能可以实现所需的功能:

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 []

此实现使用递归,对OCaml编程更自然。

答案 2 :(得分:1)

这是使用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);;

<强>用法:

let all_lines = read_all_lines "input.txt";;

但是,我更喜欢逐行流式传输:

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;;

<强>用法:

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

可能有点结冰:

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};;

<强>用法:

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

希望这有帮助!

答案 3 :(得分:1)

使用Scanf&#34;字符串指示&#34;从文件中读取行的另一种样式和零宽度字符。这就像传统的命令式风格。

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

注:

  1. read_line忽略一个尾随\ n,所以如果你的文件的最后一个字符 是\ n,似乎你错过了最后一个空行。
  2. 使用Scanf时,由于缓冲,请勿在同一通道上混用其他低电平读数,否则会导致奇怪的行为。

答案 4 :(得分:1)

这将读取文件的行并打印每一行:

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

答案 5 :(得分:0)

Std.input_list显然需要Extlib,您应该在系统上安装libextlib-ocamllibextlib-ocaml-dev在Debian系统上。

答案 6 :(得分:0)

这是一个简单的递归解决方案,它不会累积行或使用外部库,但是让您读取一行,使用函数处理它,递归读取下一个直到完成,然后干净地退出。 exit函数关闭打开的文件句柄并向调用程序发出成功信号。

let read_lines file process =
  let in_ch = open_in file in
  let rec read_line () =
    let line = try input_line in_ch with End_of_file -> exit 0
    in (* process line in this block, then read the next line *)
       process line;
       read_line ();
in read_line ();;

read_lines some_file print_endline;;

答案 7 :(得分:0)

这只是将整个文件加载到一个大字符串中,但您可以随时将其拆分为一个列表。

let read_file path =
  let channel = open_in path in
  let buffer = Buffer.create 1024 in
  let rec go () =
    try
      Buffer.add_channel buffer channel 1024; go ()
    with End_of_file ->
      Buffer.contents buffer in
  go ();;
相关问题