Reputation: 133
I have a built a function which takes as input a string and output a string.
Let's call it f
.
I would like to scan the string into a file input.txt
and apply my function on this string and write it on another file output.txt
.
Other questions: If the file is too big, maybe the scanning is impossible. Thus I have a function f_line
, and I would like to scan one by one each line of input.txt
and apply this function to this line, and write each output in the file in the file output.txt
.
How can I do that?
Upvotes: 0
Views: 384
Reputation: 133
I've finally found an easy solution with the following code :
let transform_files_by_line
(f_line : string -> string)
(in_filename : string)
(out_filename : string) =
let input_chan = open_in in_filename
and output_chan = open_out out_filename
in
let rec transform_rec () =
let str = input_line input_chan in
output_string output_chan (f_line str);
transform_rec ();
in
try
transform_rec ()
with
End_of_file -> (
close_in input_chan;
close_out output_chan;
);;
Upvotes: 0
Reputation: 35280
You basically want to map a file with your function to another file, much like you map lists, e.g.,
# List.map String.uppercase_ascii ["hello"; "world"];;
- : string list = ["HELLO"; "WORLD"]
In OCaml, files are read and written via an abstraction called a channel. Channels have directions, i.e., input channels are distinguished from the output channels. To open an input channel use the open_in
function, to close it, use close_in
. The corresponding functions for the output channels have the _out
prefix.
To map two channels line by line, we need to read a line from one channel, apply our transformation f
to each line and write to the output channel, until the first channel raises the End_of_file
exception that indicates that there is no more data, e.g.,
let rec map_channels input output f =
match f (input_line input) with
| exception End_of_file -> flush output
| r ->
output_string output r;
output_char output '\n';
map_channels input output f
Now we can use this function to write a function that takes filenames, instead of channels, e.g.,
let map_files input output f =
if input = output
then invalid_arg "the input and output files must differ";
let input = open_in input in
let output = open_out output in
map_channels input output f;
close_in input;
close_out output
Notice, that we are checking that input and output files are different to prevent mapping the file to itself, which might end up in an infinite loop and may corrupt files.
Upvotes: 2