Read a number of bytes from a stream

I’m using: SWI-Prolog version 9.1.16

I want the code to: read a number of bytes from a file

But what I’m getting is: either characters, or copying from on one stream to another

The question: do we have a predicate for reading from a stream to a Prolog data structure (list of codes?) that takes a “number of bytes” argument?

I found copy_stream_data/3 which almost does it, but now my data is another stream :slight_smile:

There are many predicates that read from streams, but I didn’t find any that takes a length parameter.

There is read_string/3, but I am not sure if this way of using it is officially supported. Here is an example of how it did what I need:

?- new_memory_file(M),
   insert_memory_file(M, 0, [1,2,0,0,4]),
   setup_call_cleanup(open_memory_file(M, read, In, [encoding(octet)]),
       read_string(In, 3, Str),
   string_codes(Str, Bytes). 
M = <memory_file>(0x6000009dc8f0),
In = <stream>(0x600000ed8200),
Str = "\u0001\u0002\u0000",
Bytes = [1, 2, 0].

I double-checked that this works for ordinary files, too:

$ echo -e '\x01\x02\x00\x00\x03' > foo
$ swipl -q
?- setup_call_cleanup(open(foo, read, In, [encoding(octet)]),
       read_string(In, 3, Str),
   string_codes(Str, Bytes).
In = <stream>(0x60000373c200),
Str = "\u0001\u0002\u0000",
Bytes = [1, 2, 0].

However, the docs explicitly warn against this:

Note that characters must be read as Unicode code points, not bytes.

Should I avoid using read_string/3 for this? Is there a predicate I overlooked that can be used instead? Or do I go ahead and use get_byte/2 in a loop?

I think that is fine. The docs are a bit misleading. read_string/3 reads characters, each of which may be multiple bytes. If you use an encoding where a character is a byte, you are (thus) fine.

This is an opportunity to add an example to read_string/3. I will make a PR soon™.

1 Like