module IO
Overview
The IO module is the basis for all input and output in Crystal.
This module is included by types like File, Socket and MemoryIO and
provide many useful methods for reading to and writing from an IO, like #print, #puts,
#gets and #printf.
The only requirement for a type including the IO module is to define these two methods:
#read(slice : Slice(UInt8)): read at most slice.size bytes into slice and return the number of bytes read#write(slice : Slice(UInt8)): write the whole slice into the IO
For example, this is a simple IO on top of a Slice(UInt8):
class SimpleSliceIO
include IO
def initialize(@slice : Slice(UInt8))
end
def read(slice : Slice(UInt8))
slice.size.times { |i| slice[i] = @slice[i] }
@slice += slice.size
count
end
def write(slice : Slice(UInt8))
slice.size.times { |i| @slice[i] = slice[i] }
@slice += slice.size
nil
end
end
slice = Slice.new(9) { |i| ('a'.ord + i).to_u8 }
String.new(slice) # => "abcdefghi"
io = SimpleSliceIO.new(slice)
io.gets(3) # => "abc"
io.print "xyz"
String.new(slice) # => "abcxyzghi"
Encoding
An IO can be set an encoding with the #set_encoding method. When this is
set, all string operations (#gets, #gets_to_end, #read_char, #<<, #print, #puts
#printf) will write in the given encoding, and read from the given encoding.
Byte operations (#read, #write, #read_byte, #write_byte) never do
encoding/decoding operations.
If an encoding is not set, the default one is UTF-8.
Mixing string and byte operations might not give correct results and should be avoided, as string operations might need to read extra bytes in order to get characters in the given encoding.
Included Modules
Direct including types
- HTTP::Server::Response
- HTTP::WebSocket::Protocol::StreamIO
- IO::Buffered
- JSON::PrettyWriter
- MemoryIO
- OpenSSL::SSL::Socket
- PointerIO
- String::Builder
- Zlib::Deflate
- Zlib::Inflate
Defined in:
io.crio/console.cr
io/encoding.cr
io/error.cr
json/to_json.cr
Class Method Summary
-
.copy(src, dst, limit : Int)
Copy at most limit bytes from src to dst.
-
.copy(src, dst)
Copy all contents from src to dst.
-
.pipe(read_blocking = false, write_blocking = false, &block)
Creates a pair of pipe endpoints (connected to each other) and passes them to the given block.
-
.pipe(read_blocking = false, write_blocking = false)
Creates a pair of pipe endpoints (connected to each other) and returns them as a two-element tuple.
-
.select(read_ios, write_ios, error_ios, timeout_sec : LibC::TimeT | Int | Float | Nil)
Returns an array of all given IOs that are * ready to read if they appeared in read_ios * ready to write if they appeared in write_ios * have an error condition if they appeared in error_ios
- .select(read_ios, write_ios = nil, error_ios = nil)
Instance Method Summary
-
#<<(obj) : self
Writes the given object into this IO.
-
#close
Closes this IO.
-
#closed?
Returns
trueif this IO is closed. - #cooked(&block)
- #cooked!
-
#each_byte
Returns an
Iteratorfor the bytes in this IO. -
#each_byte(&block)
Inovkes the given block with each byte (
UInt8) in this IO. -
#each_char(&block)
Inovkes the given block with each
Charin this IO. -
#each_char
Returns an
Iteratorfor the chars in this IO. - #each_line(*args, **options)
-
#each_line(*args, **options, &block)
Invokes the given block with each line in this IO, where a line is defined by the arguments passed to this method, which can be the same ones as in the
#getsmethods. -
#encoding : String
Returns this IO's encoding.
-
#flush
Flushes buffered data, if any.
-
#gets(limit : Int) : String | Nil
Reads a line of at most
limitbytes from this IO. -
#gets(delimiter : Char, limit : Int) : String | Nil
Reads until delimiter is found,
limitbytes are read, or the end of the IO is reached. -
#gets(delimiter : Char) : String | Nil
Reads until delimiter is found, or the end of the IO is reached.
-
#gets : String | Nil
Reads a line from this IO.
-
#gets(delimiter : String) : String | Nil
Reads until delimiter is found or the end of the IO is reached.
-
#gets_to_end : String
Reads the rest of this IO data as a
String. -
#print(obj) : Nil
Same as
#<< -
#print(*objects : _) : Nil
Writes the given objects into this IO by invoking
to_s(io)on each of the objects. - #printf(format_string, *args) : Nil
- #printf(format_string, args : Array | Tuple) : Nil
-
#puts : Nil
Writes a newline character.
-
#puts(*objects : _) : Nil
Writes the given objects, each followed by a newline character.
-
#puts(string : String) : Nil
Writes the given string to this IO followed by a newline character unless the string already ends with one.
-
#puts(obj) : Nil
Writes the given object to this IO followed by a newline character.
- #raw(&block)
- #raw!
-
#read(slice : Slice(UInt8))
Reads at most slice.size bytes from this IO into slice.
-
#read_byte : UInt8 | Nil
Reads a single byte from this IO.
-
#read_bytes(type, format : IO::ByteFormat = IO::ByteFormat::SystemEndian)
Reads an instance of the given type from this IO using the specified format.
-
#read_char : Char | Nil
Reads a single
Charfrom this IO. -
#read_fully(slice : Slice(UInt8))
Tries to read exactly
slice.sizebytes from this IO intoslice. - #read_line(*args, **options) : String | Nil
- #read_nonblock(size)
-
#read_utf8(slice : Slice(UInt8))
Reads UTF-8 decoded bytes into the given slice.
-
#read_utf8_byte
Reads a single decoded UTF-8 byte from this IO.
-
#rewind
Rewinds this IO.
-
#set_encoding(encoding : String, invalid : Symbol | Nil = nil)
Sets the encoding of this IO.
-
#skip(bytes_count : Int) : Nil
Reads and discards bytes_count bytes.
-
#tty? : Bool
Returns
trueif this IO is associated with a terminal device (tty),falseotherwise. -
#write(slice : Slice(UInt8)) : Nil
Writes the contents of slice into this IO.
-
#write_byte(byte : UInt8)
Writes a single byte into this IO.
-
#write_bytes(object, format : IO::ByteFormat = IO::ByteFormat::SystemEndian)
Writes the given object to this IO using the specified format.
-
#write_utf8(slice : Slice(UInt8))
Writes a slice of UTF-8 encoded bytes to this IO, using the current encoding.
Macro Summary
Instance methods inherited from module JSON::Builder
json_array(&block)
json_array,
json_object(&block)
json_object
Class Method Detail
Copy at most limit bytes from src to dst.
io = MemoryIO.new "hello"
io2 = MemoryIO.new
IO.copy io, io2, 3
io2.to_s # => "hel"Copy all contents from src to dst.
io = MemoryIO.new "hello"
io2 = MemoryIO.new
IO.copy io, io2
io2.to_s # => "hello"Creates a pair of pipe endpoints (connected to each other) and passes them to the given block. Both endpoints are closed after the block.
IO.pipe do |reader, writer|
writer.puts "hello"
writer.puts "world"
reader.gets # => "hello"
reader.gets # => "world"
endCreates a pair of pipe endpoints (connected to each other) and returns them as a two-element tuple.
reader, writer = IO.pipe
writer.puts "hello"
writer.puts "world"
reader.gets # => "hello"
reader.gets # => "world"Returns an array of all given IOs that are
- ready to read if they appeared in read_ios
- ready to write if they appeared in write_ios
- have an error condition if they appeared in error_ios
If the optional timeout_sec is given, nil is returned if no IO was ready after the specified amount of seconds passed. Fractions are supported.
If timeout_sec is nil, this method blocks until an IO is ready.
Instance Method Detail
Writes the given object into this IO.
This ends up calling to_s(io) on the object.
io = MemoryIO.new
io << 1
io << '-'
io << "Crystal"
io.to_s # => "1-Crystal"Returns true if this IO is closed.
IO defines returns false, but including types may override.
Returns an Iterator for the bytes in this IO.
io = MemoryIO.new("aあ")
iter = io.each_byte
iter.next # => 97
iter.next # => 227
iter.next # => 129
iter.next # => 130Inovkes the given block with each byte (UInt8) in this IO.
io = MemoryIO.new("aあ")
io.each_byte do |byte|
puts byte
end
Output:
97
227
129
130Inovkes the given block with each Char in this IO.
io = MemoryIO.new("あめ")
io.each_char do |char|
puts char
end
Output:
あ
めReturns an Iterator for the chars in this IO.
io = MemoryIO.new("あめ")
iter = io.each_char
iter.next # => 'あ'
iter.next # => 'め'Returns an Iterator for the lines in this IO, where a line
is defined by the arguments passed to this method, which can be the same
ones as in the #gets methods.
io = MemoryIO.new("hello\nworld")
iter = io.each_line
iter.next # => "hello\n"
iter.next # => "world"Invokes the given block with each line in this IO, where a line
is defined by the arguments passed to this method, which can be the same
ones as in the #gets methods.
io = MemoryIO.new("hello\nworld")
io.each_line do |line|
puts line.chomp.reverse
end
Output:
olleh
dlrowFlushes buffered data, if any.
IO defines this is a no-op method, but including types may override.
Reads a line of at most limit bytes from this IO. A line is terminated by the \n character.
Returns nil if called at the end of this IO.
io = MemoryIO.new "hello\nworld"
io.gets(3) # => "hel"
io.gets(3) # => "lo\n"
io.gets(3) # => "wor"
io.gets(3) # => "ld"
io.gets(3) # => nilReads until delimiter is found, limit bytes are read, or the end of the IO is reached.
Returns nil if called at the end of this IO.
io = MemoryIO.new "hello\nworld"
io.gets('o', 3) # => "hel"
io.gets('r', 10) # => "lo\nwor"
io.gets('z', 10) # => "ld"
io.gets('w', 10) # => nilReads until delimiter is found, or the end of the IO is reached.
Returns nil if called at the end of this IO.
io = MemoryIO.new "hello\nworld"
io.gets('o') # => "hello"
io.gets('r') # => "\nwor"
io.gets('z') # => "ld"
io.gets('w') # => nilReads a line from this IO. A line is terminated by the \n character.
Returns nil if called at the end of this IO.
io = MemoryIO.new "hello\nworld"
io.gets # => "hello\n"
io.gets # => "world"
io.gets # => nilReads until delimiter is found or the end of the IO is reached.
Returns nil if called at the end of this IO.
io = MemoryIO.new "hello\nworld"
io.gets("wo") # => "hello\nwo"
io.gets("wo") # => "rld"
io.gets("wo") # => nilReads the rest of this IO data as a String.
io = MemoryIO.new "hello world"
io.gets_to_end # => "hello world"
io.gets_to_end # => ""Same as #<<
io = MemoryIO.new
io.print 1
io.print '-'
io.print "Crystal"
io.to_s # => "1-Crystal"Writes the given objects into this IO by invoking to_s(io)
on each of the objects.
io = MemoryIO.new
io.print 1, '-', "Crystal"
io.to_s # => "1-Crystal"Writes a newline character.
io = MemoryIO.new
io.puts
io.to_s # => "\n"Writes the given objects, each followed by a newline character.
io = MemoryIO.new
io.puts 1, '-', "Crystal"
io.to_s # => "1\n-\nCrystal\n"Writes the given string to this IO followed by a newline character unless the string already ends with one.
io = MemoryIO.new
io.puts "hello\n"
io.puts "world"
io.to_s # => "hello\nworld\n"Writes the given object to this IO followed by a newline character.
io = MemoryIO.new
io.puts 1
io.puts "Crystal"
io.to_s # => "1\nCrystal\n"Reads at most slice.size bytes from this IO into slice. Returns the number of bytes read.
io = MemoryIO.new "hello"
slice = Slice(UInt8).new(4)
io.read(slice) # => 4
slice # => [104, 101, 108, 108]
io.read(slice) # => 1
slice # => [111, 101, 108, 108]Reads a single byte from this IO. Returns nil if there is no more
data to read.
io = MemoryIO.new "a"
io.read_byte # => 97
io.read_byte # => nilReads an instance of the given type from this IO using the specified format.
This ends up invoking type.from_io(self, format), so any type defining a
from_io(io : IO, format : IO::ByteFormat = IO::ByteFormat::SystemEndian)
method can be read in this way.
See Int#from_io and Float#from_io.
io = MemoryIO.new
io.puts "\u{4}\u{3}\u{2}\u{1}"
io.rewind
io.read_bytes(Int32, IO::ByteFormat::LittleEndian) # => 0x01020304Reads a single Char from this IO. Returns nil if there is no
more data to read.
io = MemoryIO.new "あ"
io.read_char # => 'あ'
io.read_char # => nilTries to read exactly slice.size bytes from this IO into slice.
Raises EOFError if there aren't slice.size bytes of data.
io = MemoryIO.new "123451234"
slice = Slice(UInt8).new(5)
io.read_fully(slice)
slice # => [49, 50, 51, 52, 53]
io.read_fully # => EOFErrorReads UTF-8 decoded bytes into the given slice. Returns the number of UTF-8 bytes read.
If no encoding is set, this is the same as #read(slice).
bytes = "你".encode("GB2312") # => [196, 227]
io = MemoryIO.new(bytes)
io.set_encoding("GB2312")
buffer = uninitialized UInt8[1024]
bytes_read = io.read_utf8(buffer.to_slice) # => 3
buffer.to_slice[0, bytes_read] # => [228, 189, 160]
"你".bytes # => [228, 189, 160]Reads a single decoded UTF-8 byte from this IO. Returns nil if there is no more
data to read.
If no encoding is set, this is the same as #read_byte.
bytes = "你".encode("GB2312") # => [196, 227]
io = MemoryIO.new(bytes)
io.set_encoding("GB2312")
io.read_utf8_byte # => 228
io.read_utf8_byte # => 189
io.read_utf8_byte # => 160
io.read_utf8_byte # => nil
"你".bytes # => [228, 189, 160]Sets the encoding of this IO.
The invalid argument can be:
nil: an exception is raised on invalid byte sequences:skip: invalid byte sequences are ignored
String operations (#gets, #gets_to_end, #read_char, #<<, #print, #puts
#printf) will use this encoding.
Reads and discards bytes_count bytes.
io = MemoryIO.new "hello world"
io.skip(6)
io.gets # => "world"Returns true if this IO is associated with a terminal device (tty), false otherwise.
IO returns false, but including types may override.
STDIN.tty? # => true
MemoryIO.new.tty? # => falseWrites the contents of slice into this IO.
io = MemoryIO.new
slice = Slice(UInt8).new(4) { |i| ('a'.ord + i).to_u8 }
io.write(slice)
io.to_s #=> "abcd"Writes a single byte into this IO.
io = MemoryIO.new
io.write_byte 97_u8
io.to_s # => "a"Writes the given object to this IO using the specified format.
This ends up invoking object.to_io(self, format), so any object defining a
to_io(io : IO, format : IO::ByteFormat = IO::ByteFormat::SystemEndian)
method can be written in this way.
See Int#to_io and Float#to_io.
io = MemoryIO.new
io.write_bytes(0x01020304, IO::ByteFormat::LittleEndian)
io.rewind
io.gets(4) # => "\u{4}\u{3}\u{2}\u{1}"Writes a slice of UTF-8 encoded bytes to this IO, using the current encoding.