Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在OCaml中读取文本文件中的行?_Ocaml - Fatal编程技术网

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

如何在OCaml中读取文本文件中的行?,ocaml,Ocaml,这就是我目前所拥有的。这不就是你所需要的吗?我一直收到错误“error:unboundmodulestd” 仅使用标准库的必要解决方案: 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 -> cl

这就是我目前所拥有的。这不就是你所需要的吗?我一直收到错误“error:unboundmodulestd”


仅使用标准库的必要解决方案:

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 ;;
如果您拥有该库,则可以将文件读入Enum.t并按如下方式对其进行迭代:

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

Std.input\u list
显然需要,您应该将其安装到您的系统上(
libextlib ocaml
libextlib ocaml dev
在Debian系统上)。

下面是一个使用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 read_next = make_reader "input.txt";;
let next_line = read_next ();;
let r = make_reader "input.txt";;
let next_line = r.read_next ();;
但是,我更喜欢一行一行地流:

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 all_lines = read_all_lines "input.txt";;
let read_next = make_reader "input.txt";;
let next_line = read_next ();;
let r = make_reader "input.txt";;
let next_line = r.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 all_lines = read_all_lines "input.txt";;
let read_next = make_reader "input.txt";;
let next_line = read_next ();;
let r = make_reader "input.txt";;
let next_line = r.read_next ();;

希望这有帮助

使用Scanf“字符串标记”和零宽度字符从文件中读取行的另一种样式。这就像传统的命令式风格

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
注:

  • read\u line忽略一个尾随字符\n,因此如果文件的最后一个字符 是\n,您可能错过了最后一行空行
  • 使用Scanf时,由于缓冲作用,请勿在同一通道上混合其他低电平读数,否则会导致奇怪的行为

  • 如果您安装了OCaml核心库,那么它就非常简单:

    open Core.Std
    let r file = In_channel.read_lines file
    
    如果已经安装了
    corebuild
    ,则可以使用它编译代码:

    corebuild filename.byte
    
    如果您的代码驻留在名为
    filename.ml
    的文件中

    如果您没有OCaml核心,或者不想安装它,或者其他一些标准库实现,那么当然,您可以使用普通的OCaml标准库来实现它。有一个函数
    input_line
    ,在
    pervisives
    模块中定义,在所有OCaml程序中自动打开(即,无需进一步说明模块名称即可访问其所有定义)。此函数在_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编程来说更自然

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

    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
    

    这里是一个简单的递归解决方案,它不累积行或使用外部库,但允许您读取一行,使用函数处理它,递归读取下一行,直到完成,然后干净地退出。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;;
    

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

    让我们读取文件路径=
    让通道=在路径中打开
    让buffer=buffer.create 1024英寸
    让rec走()=
    尝试
    Buffer.add_通道Buffer通道1024;去()
    带有\u文件的结尾\u->
    Buffer.contents缓冲区位于
    go();;
    
    …类似地,格式字符串中的换行符与单行换行符或后跟换行符的回车符匹配,因此,此解决方案“应该”适用于“\r\n”和“\n”样式的行尾(仅在Linux系统上测试)。所有代码段都不会关闭输入通道,因此会泄漏文件descriptors@ygrek:谢谢!固定的。可能最好让调用方执行打开/关闭业务,并让这些函数代替输入通道。在extlib变量中检测到fd泄漏:输入通道未关闭您可以解释为什么要用空列表链接while循环吗?我认为它永远也达不到。@Rizo这是为了让打字系统开心。尝试在REPL中输入该代码,而不使用[](在完成之后;),您将得到:错误:此表达式具有类型字节列表,但表达式的类型应为unit。使用[]时,“try”块和“With”块都会返回一个列表。@Rizo:可能最好放一个!完成后的行,但正如您所注意到的,这并不重要,因为代码永远不会被访问。不过,我会编辑上面的答案,这样做更有意义。感谢递归实现!除了“List.rev acc in loop[]”之外,我似乎了解您的大部分代码。你能解释一下到底发生了什么吗?列表中的数据是预先准备好的,所以实际上我们可以把
    acc
    看作一个堆栈。当我们完成循环(即,达到停止条件)时,我们反转堆栈,以便我们的函数以正常顺序返回数据