1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
let read_lines ?(buffer_size = 65536) filename =
let ic = open_in filename in
Fun.protect ~finally:(fun () -> close_in ic) @@ fun () ->
let buffer = Bytes.create buffer_size in
let lines = ref [] in
let current_line = Buffer.create 256 in
let rec read_buffer () =
let bytes_read = input ic buffer 0 buffer_size in
if bytes_read = 0 then (
if
Buffer.length current_line > 0
then lines := Buffer.contents current_line :: !lines)
else
let rec process_bytes pos =
if pos < bytes_read then
let c = Bytes.get buffer pos in
if c = '\n' then (
lines := Buffer.contents current_line :: !lines;
Buffer.clear current_line;
process_bytes (pos + 1))
else if c <> '\r' then (
Buffer.add_char current_line c;
process_bytes (pos + 1))
else process_bytes (pos + 1)
in
process_bytes 0;
read_buffer ()
in
read_buffer ();
List.rev !lines
let read_lines_lazy ?(buffer_size = 65536) filename =
let ic = open_in filename in
let buffer = Bytes.create buffer_size in
let buffer_pos = ref 0 in
let bytes_in_buffer = ref 0 in
let current_line = Buffer.create 256 in
let eof_reached = ref false in
let next_line () =
if !eof_reached then (
close_in ic;
None)
else
let rec find_line () =
if !buffer_pos >= !bytes_in_buffer then (
bytes_in_buffer := input ic buffer 0 buffer_size;
buffer_pos := 0;
if !bytes_in_buffer = 0 then (
eof_reached := true;
if Buffer.length current_line > 0 then (
let line = Buffer.contents current_line in
Buffer.clear current_line;
Some line)
else (
close_in ic;
None))
else find_line ())
else
let c = Bytes.get buffer !buffer_pos in
incr buffer_pos;
if c = '\n' then (
let line = Buffer.contents current_line in
Buffer.clear current_line;
Some line)
else if c <> '\r' then (
Buffer.add_char current_line c;
find_line ())
else find_line ()
in
find_line ()
in
Seq.unfold (fun () -> Option.map (fun line -> (line, ())) (next_line ())) ()
let write_lines ?(append = false) filename lines =
let oc =
if append then
open_out_gen
[ Open_wronly; Open_append; Open_creat; Open_text ]
0o644 filename
else open_out filename
in
Fun.protect ~finally:(fun () -> close_out oc) @@ fun () ->
List.iter
(fun line ->
output_string oc line;
output_char oc '\n')
lines