如何在OCaml中读取文本文件中的行?
这就是我目前所拥有的。这不就是你所需要的吗?我一直收到错误“error:unboundmodulestd”如何在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
仅使用标准库的必要解决方案:
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
注:
如果您安装了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
看作一个堆栈。当我们完成循环(即,达到停止条件)时,我们反转堆栈,以便我们的函数以正常顺序返回数据