Crystal reading x bytes from file

2019-07-09 02:06发布

问题:

I have this code:

a = File.open("/dev/urandom")
b = a.read(1024)
a.close

puts b

I expected to get the first 1024 bytes from the /dev/urandom device\file, instead I got an Error which says read accepts only slice and not Integer.

So I tried to do it like that:

b = a.read(("a" * 1000).to_slice)

But then I got back "1000" in the output.

What is the right way to read x bytes from a file in Crystal ?

回答1:

What you did is not very ideal, but it actually worked. IO#read(Slice(UInt8)) returns the number of bytes actually read, in case the file is smaller than what you requested or the data isn't available for some other reason. In other words, it's a partial read. So you get 1000 in b because the slice you passed was filled with 1000 bytes. There's IO#read_fully(Slice(UInt8)) which blocks until it fulfilled as much of the request as possible, but too can't guarantee it in any case.

A better approach looks like this:

File.open("/dev/urandom") do |io|
  buffer = Bytes.new(1000) # Bytes is an alias for Slice(UInt8)
  bytes_read = io.read(buffer)
  # We truncate the slice to what we actually got back,
  # /dev/urandom never blocks, so this isn't needed in this specific
  # case, but good practice in general
  buffer = buffer[0, bytes_read] 
  pp buffer
end

IO also provides various convenience functions for reading strings until specific tokens or up to a limit, in various encodings. Many types also implement the from_io interface, which allows you to easily read structured data.