# Why is there an output\_string but not a read\_string function?

**URL:** https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284
**Category:** Learning
**Created:** [February 5, 2019, 11:57am UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284 "2019-02-05T11:57:53Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![jonathandoyle](https://avatars.discourse-cdn.com/v4/letter/j/a3d4f5/32.png) [@jonathandoyle](https://discuss.ocaml.org/u/jonathandoyle)
#### Post date: [February 5, 2019, 11:57am UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/1 "2019-02-05T11:57:53Z")

</div>

In the Pervasives module, we have an `output_string` which takes care of writing a string on an output channel, even if the string is huge.

On the other hand, there is no `read_string:in_channel -> string` function that reads all the remaining text in an input channel (assuming it corresponds to a text file).

Is this deliberate ? I would naively have thought that reading and writing are rather symmetrical operations.

---

<div class="post-metadata">

### Author: ![Freyr666](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/freyr666/32/591_2.png) [@Freyr666](https://discuss.ocaml.org/u/Freyr666)
#### Post date: [February 5, 2019, 2:04pm UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/2 "2019-02-05T14:04:23Z")

</div>

What is string? The entire file? What if it’s too big/has no EOF?

---

<div class="post-metadata">

### Author: ![jonathandoyle](https://avatars.discourse-cdn.com/v4/letter/j/a3d4f5/32.png) [@jonathandoyle](https://discuss.ocaml.org/u/jonathandoyle)
#### Post date: [February 5, 2019, 2:18pm UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/3 "2019-02-05T14:18:01Z")

</div>

> [@Freyr666](#):
>
> The entire file? What if it’s too big/has no EOF?

It shouldn’t be hard to raise exceptions in those cases, should it ? It’s not very difficult to write a small function that does that, but I’m surprised that it’s not builtin.

---

<div class="post-metadata">

### Author: ![c-cube](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/c-cube/32/1727_2.png) [@c-cube](https://discuss.ocaml.org/u/c-cube)
#### Post date: [February 5, 2019, 2:47pm UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/4 "2019-02-05T14:47:21Z")

</div>

I’m glad you asked, someone motivated could definitely  
try and revive [https://github.com/ocaml/ocaml/pull/640](https://github.com/ocaml/ocaml/pull/640) which adds some  
helpers to the stdlib’s IO. Good luck!

---

<div class="post-metadata">

### Author: ![jonathandoyle](https://avatars.discourse-cdn.com/v4/letter/j/a3d4f5/32.png) [@jonathandoyle](https://discuss.ocaml.org/u/jonathandoyle)
#### Post date: [February 5, 2019, 2:51pm UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/5 "2019-02-05T14:51:17Z")

</div>

> [@c-cube](#):
>
> I’m glad you asked

I’m glad other people share my concerns too 🙂

---

<div class="post-metadata">

### Author: ![UnixJunkie](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/unixjunkie/32/638_2.png) [@UnixJunkie](https://discuss.ocaml.org/u/UnixJunkie)
#### Post date: [February 7, 2019, 1:52am UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/6 "2019-02-07T01:52:23Z")

</div>

Indeed, this is quite useful when doing system programming.  
Several libraries define such a function.  
It is named string\_of\_file usually.  
For example:

```auto
opam install ocaml-compiler-libs

```

Then use Misc.string\_of\_file.

---

<div class="post-metadata">

### Author: ![Leonidas](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/leonidas/32/4039_2.png) [@Leonidas](https://discuss.ocaml.org/u/Leonidas)
#### Post date: [February 7, 2019, 9:21am UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/7 "2019-02-07T09:21:11Z")

</div>

> [@jonathandoyle](#):
>
> It shouldn’t be hard to raise exceptions in those cases, should it ?

It is not too hard, because it is impossible to do “correctly”. The read operation on a file might block forever, e.g. a file on an NFS mount on a connection that went away.

---

<div class="post-metadata">

### Author: ![Armael](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/armael/32/1223_2.png) [@Armael](https://discuss.ocaml.org/u/Armael)
#### Post date: [February 7, 2019, 10:02am UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/8 "2019-02-07T10:02:40Z")

</div>

I must point out that “compiler libs” (the set of modules that are part of the compiler implementation) give currently _no guarantee_ about the stability of their API. You should only use it if you really need it and you know what you are doing.  
So for a simple function such as `string_of_file` that can be implemented independently from the compiler codebase, you really should use any other library (containers, bos, base) instead of compiler libs.

---

<div class="post-metadata">

### Author: ![mseri](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/mseri/32/91_2.png) [@mseri](https://discuss.ocaml.org/u/mseri)
#### Post date: [February 7, 2019, 12:49pm UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/9 "2019-02-07T12:49:41Z")

</div>

Or we could try to get @c-cube PR merged in the stdlib.

---

<div class="post-metadata">

### Author: ![Armael](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/armael/32/1223_2.png) [@Armael](https://discuss.ocaml.org/u/Armael)
#### Post date: [February 7, 2019, 12:58pm UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/10 "2019-02-07T12:58:51Z")

</div>

Sure, that would be nice as well.

---

<div class="post-metadata">

### Author: ![c-cube](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/c-cube/32/1727_2.png) [@c-cube](https://discuss.ocaml.org/u/c-cube)
#### Post date: [February 7, 2019, 3:08pm UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/11 "2019-02-07T15:08:18Z")

</div>

Serious question: is anyone motivated to take the PR over? (not sure how easy it can be).

---

<div class="post-metadata">

### Author: ![Chet\_Murthy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/chet_murthy/32/1501_2.png) [@Chet\_Murthy](https://discuss.ocaml.org/u/Chet_Murthy)
#### Post date: [January 21, 2020, 3:13am UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/12 "2020-01-21T03:13:03Z")

</div>

[oh, I see you really -do- mean “read the whole file into a string”]

This might make sense to put in a bolt-on library, but why would one put it in the core?

1. it’s trivial to implement with really\_input, a fixed-size read buffer, and the Buffer module.
2. for anybody who doesn’t know what they’re doing, it’s a loaded gun lying around.
3. For anybody who _does_ know what they’re doing, see #1.

---

<div class="post-metadata">

### Author: ![UnixJunkie](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/unixjunkie/32/638_2.png) [@UnixJunkie](https://discuss.ocaml.org/u/UnixJunkie)
#### Post date: [January 21, 2020, 6:41am UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/13 "2020-01-21T06:41:58Z")

</div>

I found this code in my DAFT project:

```auto
  let string_of_file fn =
    let buff_size = 1024 in
    let buff = Buffer.create buff_size in
    let ic = open_in fn in
    let line_buff = Bytes.create buff_size in
    begin
      let was_read = ref (input ic line_buff 0 buff_size) in
      while !was_read <> 0 do
        Buffer.add_subbytes buff line_buff 0 !was_read;
        was_read := input ic line_buff 0 buff_size;
      done;
      close_in ic;
    end;
    Buffer.contents buff

```

---

<div class="post-metadata">

### Author: ![Chet\_Murthy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/chet_murthy/32/1501_2.png) [@Chet\_Murthy](https://discuss.ocaml.org/u/Chet_Murthy)
#### Post date: [January 21, 2020, 6:43am UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/14 "2020-01-21T06:43:52Z")

</div>

Yep. I used to have one in my “utils” library. But recently I started using the “Bos” library for “convenient file I/O” and it’s got nice verbs for things like this – file contents, dir contents, etc.

---

<div class="post-metadata">

### Author: ![UnixJunkie](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/unixjunkie/32/638_2.png) [@UnixJunkie](https://discuss.ocaml.org/u/UnixJunkie)
#### Post date: [January 21, 2020, 6:45am UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/15 "2020-01-21T06:45:23Z")

</div>

Ok, I found the bos:

> **[dbuenzli/bos](https://github.com/dbuenzli/bos)**
>
> Basic OS interaction for OCaml. Contribute to dbuenzli/bos development by creating an account on GitHub.

[https://erratique.ch/software/bos](https://erratique.ch/software/bos)

---

<div class="post-metadata">

### Author: ![UnixJunkie](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/unixjunkie/32/638_2.png) [@UnixJunkie](https://discuss.ocaml.org/u/UnixJunkie)
#### Post date: [January 21, 2020, 6:47am UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/16 "2020-01-21T06:47:13Z")

</div>

I do think the symmetric operation to output\_string is called input\_line in the stdlib:

```auto
val input_line in_channel -> string                                          
    Read characters from the given input channel, until a                       
    newline character is encountered. Return the string of                      
    all characters read, without the newline character at the end.              
    Raise [End_of_file] if the end of the file is reached                       
    at the beginning of line.   

```

---

<div class="post-metadata">

### Author: ![Chet\_Murthy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/chet_murthy/32/1501_2.png) [@Chet\_Murthy](https://discuss.ocaml.org/u/Chet_Murthy)
#### Post date: [January 21, 2020, 6:57am UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/17 "2020-01-21T06:57:18Z")

</div>

Yeah, that’s some sweet code there.

---

<div class="post-metadata">

### Author: ![mbacarella](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/mbacarella/32/2420_2.png) [@mbacarella](https://discuss.ocaml.org/u/mbacarella)
#### Post date: [January 22, 2020, 2:26pm UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/18 "2020-01-22T14:26:12Z")

</div>

I feel like I’m missing a punchline because nobody has mentioned `core` yet, but you can use `In_channel.input_all` if you install core.

[https://ocaml.janestreet.com/ocaml-core/109.55.00/tmp/core\_kernel/In\_channel.html](https://ocaml.janestreet.com/ocaml-core/109.55.00/tmp/core_kernel/In_channel.html)

A large group of OCaml devs has had these “wtf?” moments like yours wrt the standard library and released an overlay.

---

<div class="post-metadata">

### Author: ![bluddy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/bluddy/32/104_2.png) [@bluddy](https://discuss.ocaml.org/u/bluddy)
#### Post date: [January 22, 2020, 2:55pm UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/19 "2020-01-22T14:55:05Z")

</div>

The same thing exists in [Stdio](https://github.com/janestreet/stdio/blob/master/src/in_channel.mli), also by Jane Street.

This is an obvious need. Memory is cheap, and if you can load the entire file into a string, it makes sense to do so.

---

<div class="post-metadata">

### Author: ![c-cube](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/c-cube/32/1727_2.png) [@c-cube](https://discuss.ocaml.org/u/c-cube)
#### Post date: [January 22, 2020, 3:10pm UTC](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284/20 "2020-01-22T15:10:56Z")

</div>

There’s something like that in all and every stdlib extension or alternative, including batteries and containers! Oftentimes it’s better to load a file in its entirety, so it won’t change (e.g. if a source file won’t fit in memory, a compiler will have trouble processing it!)

[Next page](https://discuss.ocaml.org/t/why-is-there-an-output-string-but-not-a-read-string-function/3284.md?page=2)
