I want to print the contents of a file. I tried to use a string buffer:
let ch = open_in "myfile.txt" in
let buf = Buffer.create 1024 in
(try Buffer.add_channel buf ch max_int with _ -> ());
close_in ch;
let string = Buffer.contents buf
print_endline string
this just gives me a syntax error.
How can I do this?
You need to give the right channel length:
let ic = open_in "foo" in
let len = in_channel_length ic in
let buf = Buffer.create len in
Buffer.add_channel bif ic len;
let str = Buffer.contents b in
print_endline str
The only syntax error I see is a missing in after let string = Buffer.contents buf.
The purpose of Buffer.add_channel is to add exactly the given number of characters from the given channel to the buffer. Unless your file "myfile.txt" is exceptionally large, the buffer will be empty when you print it out.
In fact on my system (a 64-bit system), max_int is so large that Buffer.add_channel doesn't even try to read that much data. It raises an Invalid_argument exception.
Related
let string s = "";;
let string s =
for i = 0 to 5 do
Printf.sprintf "%s" s
done;;
I want to printf with string type in loop (ex-string "hi" -> "hihihihihi")
When I use for, It makes string to unit and It doesnt' work.
How to loop print with string type?
There are few ways to do it with a buffer or format, with the right complexity.
First, the more imperative version is probably with a buffer
let string_repeat_n_time s n =
let b = Buffer.create (String.length s * n) in
for i = 1 to n do
Buffer.add_string b s
done;
Buffer.contents b
Buffer are made to handle efficiently repeated addition, so they are the right data structure.
A more functional version would be to use recursion with Format.fprintf (Format is essentially an improved version of Printf)
let string_n_times s n =
let rec repeat ppf n =
if n = 0 then Format.fprintf ppf "%!"
else
Format.fprintf ppf "%s%a" s repeat (n-1) in
Format.asprintf "%a" repeat n ;;
This code is using a Buffer under the hood thus the complexity is the same as before. If we make the buffer explicit, we can have an imperative code that is using the format printer
let string_n_times s n =
let b = Buffer.create (String.length s * n) in
let ppf = Format.formatter_of_buffer b in
for i = 1 to n do
Format.fprintf ppf "%s" s
done;
Format.fprintf ppf "%!" (* flush *);
Buffer.contents b
which can be useful if we are adding something more complex than a string to the buffer.
Something like this:
let string_n_times s n =
let str = ref "" in
for i = 1 to n do
str := !str ^ s
done; !str
let () = print_endline (string_n_times "hi" 5)
Is this what you are trying to accomplish?
let string_n_times s n =
for i = 0 to n do
Printf.printf "%s" s
done
let () = string_n_times "Hi" 5
I have this prog parsetreetest.ml:
let ()=
let filename = "test.ml" in
Location.input_name := filename ;
let readhandle = open_in filename in
let buf = Lexing.from_channel readhandle in
Location.init buf filename ;
let ast = Parse.implementation buf in
let pstr_desc=(List.nth ast 0).pstr_desc in
match pstr_desc with
|Pstr_eval (expression,attributes)->
match expression.pexp_desc with
|Pexp_constant constant->
match constant with
|Pconst_integer (const_int,char_option)->
Printf.printf "%s" const_int;
close_in readhandle
If test.ml have only a integer,for example:1,this prog can read it and return Parsetree.
In the parsetree.mli:
and expression_desc =
| Pexp_ident of Longident.t loc
(* x
M.x
*)
| Pexp_constant of constant
(* 1, 'a', "true", 1.0, 1l, 1L, 1n *)
the Pexp_ident is paralleling to Pexp_constant,if I write parsetreetest2.ml:
let ()=
let filename = "test2.ml" in
Location.input_name := filename ;
let readhandle = open_in filename in
let buf = Lexing.from_channel readhandle in
Location.init buf filename ;
let ast = Parse.implementation buf in
let pstr_desc=(List.nth ast 0).pstr_desc in
match pstr_desc with
|Pstr_eval (expression,attributes)->
match expression.pexp_desc with
|Pexp_ident loc->
match loc with
|Lident l->
Printf.printf "%s" l;
close_in readhandle
in test2.ml I write x,as the parsetree.mli example show me,then compiler with ocamlbuild,which used to compile parsetreetest.ml success,got error:
File "parsetreetest2.ml", line 14, characters 7-13:
Error: Unbound constructor Lident
I don't know why I can't do this,thanks!
You don't show a definition for Lident so the obvious conclusion is that the constructor is undefined, which is exactly what the compiler is telling you. The case that works doesn't use Lident, so it doesn't have the error.
It sounds like you're working with some pre-existing files. So the thing to do might be to look around and find the definition of Lident and make sure it is compiled and can be found by the compiler.
If you're copying code from somewhere else, you might look to see whether there are any open declarations in the other code. Possibly an open declaration would make Lident available in your code.
I am basically trying to read a large file (around 10G) into a list of lines. The file contains a sequence of integer, something like this:
0x123456
0x123123
0x123123
.....
I used the method below to read files by default for my codebase, but it turns out to be quit slow (~12 minutes) at this scenario
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;;
I guess I need to read the file into memory, and then split them into lines (I am using a 128G server, so it should be fine for the memory space). But I still didn't understand whether OCaml provides such facility after searching the documents here.
So here is my question:
Given my situation, how to read files into string list in a fast way?
How about using stream? But I need to adjust related application code, then that could cause some time.
First of all you should consider whether you really need to have all the information at once in your memory. Maybe it is better to process file line-by-line?
If you really want to have it all at once in memory, then you can use Bigarray's map_file function to map a file as an array of characters. And then do something with it.
Also, as I see, this file contains numbers. Maybe it is better to allocate the array (or even better a bigarray) and the process each line in order and store integers in the (big)array.
I often use the two following function to read the lines of a file. Note that the function lines_from_files is tail-recursive.
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")
This should work:
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 | _ -> []
This solution converts the strings to integers as they're read in (which should be a bit more memory efficient, and I assume this was going to be done to them eventually.
Also, because it is recursive, the file must be opened outside of the function call.
I have a char list ['a';'b';'c']
How do I convert this to the string "abc"?
thanks x
You can create a string of a length, equal to the length of the list, and then fold over the list, with a counter and initialize the string with the contents of the list... But, since OCaml 4.02, the string type started to shift in the direction of immutability (and became immutable in 4.06), you should start to treat strings, as an immutable data structure. So, let's try another solution. There is the Buffer module that is use specifically for the string building:
# let buf = Buffer.create 16;;
val buf : Buffer.t = <abstr>
# List.iter (Buffer.add_char buf) ['a'; 'b'; 'c'];;
- : unit = ()
# Buffer.contents buf;;
- : string = "abc"
Or, as a function:
let string_of_chars chars =
let buf = Buffer.create 16 in
List.iter (Buffer.add_char buf) chars;
Buffer.contents buf
let cl2s cl = String.concat "" (List.map (String.make 1) cl)
Since OCaml 4.07, you can use sequences to easily do that.
let l = ['a';'b';'c'] in
let s = String.of_seq (List.to_seq l) in
assert ( s = "abc" )
Commonly used Base library also offers Base.String.of_char_list
I am trying to read a file and return the element read from the file as an input to another function.
How can I return a value when I am reading from the file??
I tried everything I am aware of and am still hopelessly lost.
My code is as follows:
let file = "code.txt";;
let oc = open_out file in (* create or truncate file, return channel *)
fprintf oc "%s\n" (play); (* write code to file returned from calling (play) function *)
close_out oc ;;
(*read from file*)
let read l=
let f x =
let ic = open_in file in
let line = input_line ic in (* read line from in_channel and discard \n *)
print_endline line; (* write the result to stdout *)
((x ^ line) :: l);
flush stdout;
close_in ic ;
in
f l
;;
prompt: read;; function call outputs:
- : unit = ()
My file contains a string which is a code needed as input for another function.
Please help. I am not sure where I am going wrong.
Thank you.
If multiple expressions are sequenced together using ; the value of the whole expression is the value of the last expression in the sequence.
So if you have something like ((x ^ line) :: l); close_in ic the value of that expression is the value of close_in ic, which is ().
Obviously that's not what you want. In order to make ((x ^ line) :: l) the result of the whole expression, you should place it after close_in ic.