package saga
Source file io.ml
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 99let read_lines ?(buffer_size = 65536) filename = let ic = open_in filename in Fun.protect ~finally:(fun () -> close_in ic) @@ fun () -> (* Pre-allocate buffer for efficiency *) 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 (* End of file - add remaining line if exists *) Buffer.length current_line > 0 then lines := Buffer.contents current_line :: !lines) else (* Process the buffer *) let rec process_bytes pos = if pos < bytes_read then let c = Bytes.get buffer pos in if c = '\n' then ( (* Complete line found *) lines := Buffer.contents current_line :: !lines; Buffer.clear current_line; process_bytes (pos + 1)) else if c <> '\r' then ( (* Add character to current line (skip \r for Windows compatibility) *) 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 () = (* Check if we need to read more data *) 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 *) 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 (* Process current buffer *) 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