将大文件读入字符串行 OCaml

Read a large file into string lines OCaml

我基本上是在尝试将一个大文件(大约 10G)读入一个行列表。该文件包含一个整数序列,如下所示:

0x123456
0x123123
0x123123
..... 

我的代码库默认使用下面的方法读取文件,但在这种情况下它退出速度很慢(~12 分钟)

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

我想我需要将文件读入内存,然后将它们拆分成行(我使用的是128G的服务器,所以内存应该没问题space)。但是我在搜索文档here.

后仍然不明白OCaml是否提供了这样的便利

所以这是我的问题:

  1. 根据我的情况,如何快速将文件读入字符串列表?

  2. 使用stream怎么样?但是我需要调整相关的应用程序代码,这可能会花费一些时间。

首先你应该考虑你是否真的需要在你的记忆中一次拥有所有的信息。也许逐行处理文件更好?

如果你真的想一次把它全部放在内存中,那么你可以使用Bigarraymap_file函数将一个文件映射为一个字符数组。然后用它做点什么。

此外,据我所知,此文件包含数字。也许最好分配数组(或者更好的是 bigarray)并按顺序处理每一行并将整数存储在(大)数组中。

这应该有效:

let rec ints_from_file fdesc =
  try
    let l = input_line fdesc in
    let l' = int_of_string l in
    l' :: ints_from_file fdesc
  with | _ -> []

此解决方案在读入字符串时将其转换为整数(这应该会提高内存效率,我认为这最终将对它们完成。

此外,因为它是递归的,所以必须在函数调用之外打开文件。

我经常使用以下两个函数来读取文件的行。请注意,函数 lines_from_files 是尾递归的。

let read_line i = try Some (input_line i) with End_of_file -> None 

let lines_from_files filename = 
  let rec lines_from_files_aux i acc = match (read_line i) with 
    | None -> List.rev acc
    | Some s -> lines_from_files_aux i (s :: acc) in 
  lines_from_files_aux (open_in filename) [] 

let () = 
  lines_from_files "foo"
  |> List.iter (Printf.printf "lines = %s\n")