abstract class IO
Overview
The IO
class is the basis for all input and output in Crystal.
This class is inherited by types like File
, Socket
and IO::Memory
and
provides many useful methods for reading from and writing to 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 : Bytes)
: read at most slice.size bytes from IO into slice and return the number of bytes read#write(slice : Bytes)
: write the whole slice into the IO
For example, this is a simple IO
on top of a Bytes
:
class SimpleSliceIO < IO
def initialize(@slice : Bytes)
end
def read(slice : Bytes)
slice.size.times { |i| slice[i] = @slice[i] }
@slice += slice.size
slice.size
end
def write(slice : Bytes) : Nil
slice.size.times { |i| @slice[i] = slice[i] }
@slice += slice.size
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
, #getb_to_end
) 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.
Direct Known Subclasses
- Compress::Deflate::Reader
- Compress::Deflate::Writer
- Compress::Gzip::Reader
- Compress::Gzip::Writer
- Compress::Zlib::Reader
- Compress::Zlib::Writer
- HTTP::Server::Response
- IO::Delimited
- IO::Digest
- IO::FileDescriptor
- IO::Hexdump
- IO::Memory
- IO::MultiWriter
- IO::Sized
- IO::Stapled
- OpenSSL::SSL::Socket
- Socket
- String::Builder
Defined in:
io.crio/encoding.cr:5
io/encoding.cr:28
io/error.cr
Constant Summary
-
DEFAULT_BUFFER_SIZE =
32768
-
Default size used for generic stream buffers.
Class Method Summary
-
.copy(src, dst, limit : Int) : Int64
Copy at most limit bytes from src to dst.
-
.copy(src, dst) : Int64
Copy all contents from src to dst.
-
.pipe(read_blocking = false, write_blocking = false) : Tuple(IO::FileDescriptor, IO::FileDescriptor)
Creates a pair of pipe endpoints (connected to each other) and returns them as a two-element
Tuple
. -
.pipe(read_blocking = false, write_blocking = false, &)
Creates a pair of pipe endpoints (connected to each other) and passes them to the given block.
-
.same_content?(stream1 : IO, stream2 : IO) : Bool
Compares two streams stream1 to stream2 to determine if they are identical.
Instance Method Summary
-
#<<(obj) : self
Writes the given object into this
IO
. -
#close
Closes this
IO
. -
#closed? : Bool
Returns
true
if thisIO
is closed. - #each_byte(&) : Nil
- #each_byte
- #each_char(&) : Nil
- #each_char
- #each_line(*args, **options, &block : String -> ) : Nil
- #each_line(*args, **options)
-
#encoding : String
Returns this
IO
's encoding. -
#flush
Flushes buffered data, if any.
- #getb_to_end : Bytes
-
#gets(limit : Int, chomp = false) : String | Nil
Reads a line of at most limit bytes from this
IO
. -
#gets(delimiter : Char, limit : Int, chomp = false) : String | Nil
Reads until delimiter is found, limit bytes are read, or the end of the
IO
is reached. -
#gets(delimiter : Char, chomp = false) : String | Nil
Reads until delimiter is found, or the end of the
IO
is reached. -
#gets(delimiter : String, chomp = false) : String | Nil
Reads until delimiter is found or the end of the
IO
is reached. -
#gets(chomp = true) : String | Nil
Reads a line from this
IO
. - #gets_to_end : String
-
#peek : Bytes | Nil
Peeks into this IO, if possible.
-
#pos
Returns the current position (in bytes) in this
IO
. -
#pos=(value)
Sets the current position (in bytes) in this
IO
. -
#print(obj : _) : Nil
Same as
<<
. -
#print(*objects : _) : Nil
Writes the given objects into this
IO
by invokingto_s(io)
on each of the objects. -
#printf(format_string, args : Array | Tuple) : Nil
Writes a formatted string to this IO.
-
#printf(format_string, *args) : Nil
Writes a formatted string to this IO.
-
#puts(string : String) : Nil
Writes string to this
IO
, followed by a newline character unless the string already ends with one. -
#puts(obj : _) : Nil
Writes obj to this
IO
, followed by a newline character. -
#puts : Nil
Writes a newline character.
- #puts(*objects : _) : Nil
-
#read(slice : Bytes)
Reads at most slice.size bytes from this
IO
into slice. -
#read_at(offset, bytesize, & : IO -> )
Yields an
IO
to read a section inside this IO. -
#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
-
#read_fully(slice : Bytes) : Int32
Tries to read exactly
slice.size
bytes from thisIO
into slice. -
#read_fully?(slice : Bytes) : Int32 | Nil
Tries to read exactly
slice.size
bytes from thisIO
into slice. - #read_line(*args, **options) : String
-
#read_string(bytesize : Int) : String
Reads an UTF-8 encoded string of exactly bytesize bytes.
-
#read_utf8(slice : Bytes)
Reads UTF-8 decoded bytes into the given slice.
-
#read_utf8_byte : UInt8 | Nil
Reads a single decoded UTF-8 byte from this
IO
. -
#rewind
Rewinds this
IO
. -
#seek(offset, whence : Seek = Seek::Set)
Seeks to a given offset (in bytes) according to the whence argument.
-
#set_encoding(encoding : String, invalid : Symbol | Nil = nil) : Nil
Sets the encoding of this
IO
. -
#skip(bytes_count : Int) : Nil
Reads and discards exactly bytes_count bytes.
-
#skip_to_end : Nil
Reads and discards bytes from
self
until there are no more bytes. -
#tell
Same as
#pos
. -
#tty? : Bool
Returns
true
if thisIO
is associated with a terminal device (tty),false
otherwise. -
#write(slice : Bytes) : Nil
Writes the contents of slice into this
IO
. -
#write_byte(byte : UInt8) : Nil
Writes a single byte into this
IO
. -
#write_bytes(object, format : IO::ByteFormat = IO::ByteFormat::SystemEndian) : Nil
Writes the given object to this
IO
using the specified format. -
#write_string(slice : Bytes) : Nil
Writes the contents of slice, interpreted as a sequence of UTF-8 or ASCII characters, into this
IO
. -
#write_utf8(slice : Bytes) : Nil
Writes the contents of slice, interpreted as a sequence of UTF-8 or ASCII characters, into this
IO
.DEPRECATED Use
#write_string
instead.
Instance methods inherited from class Reference
==(other : self)==(other : JSON::Any)
==(other : YAML::Any)
==(other) ==, dup dup, hash(hasher) hash, initialize initialize, inspect(io : IO) : Nil inspect, object_id : UInt64 object_id, pretty_print(pp) : Nil pretty_print, same?(other : Reference) : Bool
same?(other : Nil) same?, to_s(io : IO) : Nil to_s
Constructor methods inherited from class Reference
new
new
Instance methods inherited from class Object
! : Bool
!,
!=(other)
!=,
!~(other)
!~,
==(other)
==,
===(other : JSON::Any)===(other : YAML::Any)
===(other) ===, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash hash, in?(collection : Object) : Bool
in?(*values : Object) : Bool in?, inspect(io : IO) : Nil
inspect : String inspect, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil!(message)
not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO) : Nil
to_json : String to_json, to_pretty_json(indent : String = " ") : String
to_pretty_json(io : IO, indent : String = " ") : Nil to_pretty_json, to_s(io : IO) : Nil
to_s : String to_s, to_yaml(io : IO) : Nil
to_yaml : String to_yaml, try(&) try, unsafe_as(type : T.class) forall T unsafe_as
Class methods inherited from class Object
from_json(string_or_io, root : String)from_json(string_or_io) from_json, from_yaml(string_or_io : String | IO) from_yaml
Class Method Detail
Copy at most limit bytes from src to dst.
io = IO::Memory.new "hello"
io2 = IO::Memory.new
IO.copy io, io2, 3
io2.to_s # => "hel"
Copy all contents from src to dst.
io = IO::Memory.new "hello"
io2 = IO::Memory.new
IO.copy io, io2
io2.to_s # => "hello"
Creates 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"
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"
end
Compares two streams stream1 to stream2 to determine if they are identical.
Returns true
if content are the same, false
otherwise.
File.write("afile", "123")
stream1 = File.open("afile")
stream2 = IO::Memory.new("123")
IO.same_content?(stream1, stream2) # => true
Instance Method Detail
Writes the given object into this IO
.
This ends up calling to_s(io)
on the object.
io = IO::Memory.new
io << 1
io << '-'
io << "Crystal"
io.to_s # => "1-Crystal"
Invokes the given block with each byte (UInt8
) in this IO
.
io = IO::Memory.new("aあ")
io.each_byte do |byte|
puts byte
end
Output:
97
227
129
130
Returns an Iterator
for the bytes in this IO
.
io = IO::Memory.new("aあ")
iter = io.each_byte
iter.next # => 97
iter.next # => 227
iter.next # => 129
iter.next # => 130
Invokes the given block with each Char
in this IO
.
io = IO::Memory.new("あめ")
io.each_char do |char|
puts char
end
Output:
あ
め
Returns an Iterator
for the chars in this IO
.
io = IO::Memory.new("あめ")
iter = io.each_char
iter.next # => 'あ'
iter.next # => 'め'
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 = IO::Memory.new("hello\nworld")
io.each_line do |line|
puts line
end
# output:
# hello
# world
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 = IO::Memory.new("hello\nworld")
iter = io.each_line
iter.next # => "hello"
iter.next # => "world"
Flushes buffered data, if any.
IO
defines this is a no-op method, but including types may override.
Reads the rest of this IO
data as a writable Bytes
.
io = IO::Memory.new Bytes[0, 1, 3, 6, 10, 15]
io.getb_to_end # => Bytes[0, 1, 3, 6, 10, 15]
io.getb_to_end # => Bytes[]
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 = IO::Memory.new "hello\nworld"
io.gets(3) # => "hel"
io.gets(3) # => "lo\n"
io.gets(3) # => "wor"
io.gets(3) # => "ld"
io.gets(3) # => nil
Reads 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 = IO::Memory.new "hello\nworld"
io.gets('o', 3) # => "hel"
io.gets('r', 10) # => "lo\nwor"
io.gets('z', 10) # => "ld"
io.gets('w', 10) # => nil
Reads until delimiter is found, or the end of the IO
is reached.
Returns nil
if called at the end of this IO
.
io = IO::Memory.new "hello\nworld"
io.gets('o') # => "hello"
io.gets('r') # => "\nwor"
io.gets('z') # => "ld"
io.gets('w') # => nil
Reads until delimiter is found or the end of the IO
is reached.
Returns nil
if called at the end of this IO
.
io = IO::Memory.new "hello\nworld"
io.gets("wo") # => "hello\nwo"
io.gets("wo") # => "rld"
io.gets("wo") # => nil
Reads a line from this IO
. A line is terminated by the \n
character.
Returns nil
if called at the end of this IO
.
By default the newline is removed from the returned string,
unless chomp is false
.
io = IO::Memory.new "hello\nworld\nfoo\n"
io.gets # => "hello"
io.gets(chomp: false) # => "world\n"
io.gets # => "foo"
io.gets # => nil
Reads the rest of this IO
data as a String
.
io = IO::Memory.new "hello world"
io.gets_to_end # => "hello world"
io.gets_to_end # => ""
Peeks into this IO, if possible.
It returns:
nil
if this IO isn't peekable at this moment or at all- an empty slice if it is, but EOF was reached
- a non-empty slice if some data can be peeked
The returned bytes are only valid data until a next call to any method that reads from this IO is invoked.
By default this method returns nil
, but IO implementations
that provide buffering or wrap other IOs should override
this method.
Returns the current position (in bytes) in this IO
.
The IO
class raises on this method, but some subclasses, notable
IO::FileDescriptor
and IO::Memory
implement it.
File.write("testfile", "hello")
file = File.new("testfile")
file.pos # => 0
file.gets(2) # => "he"
file.pos # => 2
Sets the current position (in bytes) in this IO
.
The IO
class raises on this method, but some subclasses, notable
IO::FileDescriptor
and IO::Memory
implement it.
File.write("testfile", "hello")
file = File.new("testfile")
file.pos = 3
file.gets_to_end # => "lo"
Same as <<
.
io = IO::Memory.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 = IO::Memory.new
io.print 1, '-', "Crystal"
io.to_s # => "1-Crystal"
Writes a formatted string to this IO.
For details on the format string, see top-level ::printf
.
Writes a formatted string to this IO.
For details on the format string, see top-level ::printf
.
Writes string to this IO
, followed by a newline character
unless the string already ends with one.
io = IO::Memory.new
io.puts "hello\n"
io.puts "world"
io.to_s # => "hello\nworld\n"
Writes obj to this IO
, followed by a newline character.
io = IO::Memory.new
io.puts 1
io.puts "Crystal"
io.to_s # => "1\nCrystal\n"
Writes a newline character.
io = IO::Memory.new
io.puts
io.to_s # => "\n"
Writes objects to this IO
, each followed by a newline character unless
the object is a String
and already ends with a newline.
io = IO::Memory.new
io.puts 1, '-', "Crystal"
io.to_s # => "1\n-\nCrystal\n"
Reads at most slice.size bytes from this IO
into slice.
Returns the number of bytes read, which is 0 if and only if there is no
more data to read (so checking for 0 is the way to detect end of file).
io = IO::Memory.new "hello"
slice = Bytes.new(4)
io.read(slice) # => 4
slice # => Bytes[104, 101, 108, 108]
io.read(slice) # => 1
slice # => Bytes[111, 101, 108, 108]
io.read(slice) # => 0
Yields an IO
to read a section inside this IO.
The IO
class raises on this method, but some subclasses, notable
File
and IO::Memory
implement it.
Multiple sections can be read concurrently.
Reads a single byte from this IO
. Returns nil
if there is no more
data to read.
io = IO::Memory.new "a"
io.read_byte # => 97
io.read_byte # => nil
Reads 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 = IO::Memory.new
io.puts "\u{4}\u{3}\u{2}\u{1}"
io.rewind
io.read_bytes(Int32, IO::ByteFormat::LittleEndian) # => 0x01020304
Reads a single Char
from this IO
. Returns nil
if there is no
more data to read.
io = IO::Memory.new "あ"
io.read_char # => 'あ'
io.read_char # => nil
Tries to read exactly slice.size
bytes from this IO
into slice.
Raises EOFError
if there aren't slice.size
bytes of data.
io = IO::Memory.new "123451234"
slice = Bytes.new(5)
io.read_fully(slice) # => 5
slice # => Bytes[49, 50, 51, 52, 53]
io.read_fully(slice) # raises IO::EOFError
Tries to read exactly slice.size
bytes from this IO
into slice.
Returns nil
if there aren't slice.size
bytes of data, otherwise
returns the number of bytes read.
io = IO::Memory.new "123451234"
slice = Bytes.new(5)
io.read_fully?(slice) # => 5
slice # => Bytes[49, 50, 51, 52, 53]
io.read_fully?(slice) # => nil
Reads an UTF-8 encoded string of exactly bytesize bytes.
Raises EOFError
if there are not enough bytes to build
the string.
io = IO::Memory.new("hello world")
io.read_string(5) # => "hello"
io.read_string(1) # => " "
io.read_string(6) # raises IO::EOFError
Reads 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") # => Bytes[196, 227]
io = IO::Memory.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] # => Bytes[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") # => Bytes[196, 227]
io = IO::Memory.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]
Seeks to a given offset (in bytes) according to the whence argument.
The IO
class raises on this method, but some subclasses, notable
IO::FileDescriptor
and IO::Memory
implement it.
Returns self
.
File.write("testfile", "abc")
file = File.new("testfile")
file.gets(3) # => "abc"
file.seek(1, IO::Seek::Set)
file.gets(2) # => "bc"
file.seek(-1, IO::Seek::Current)
file.gets(1) # => "c"
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 exactly bytes_count bytes.
Raises IO::EOFError
if there aren't at least bytes_count bytes.
io = IO::Memory.new "hello world"
io.skip(6)
io.gets # => "world"
io.skip(1) # raises IO::EOFError
Reads and discards bytes from self
until there
are no more bytes.
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
IO::Memory.new.tty? # => false
Writes the contents of slice into this IO
.
io = IO::Memory.new
slice = Bytes.new(4) { |i| ('a'.ord + i).to_u8 }
io.write(slice)
io.to_s # => "abcd"
Writes a single byte into this IO
.
io = IO::Memory.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 = IO::Memory.new
io.write_bytes(0x01020304, IO::ByteFormat::LittleEndian)
io.rewind
io.gets(4) # => "\u{4}\u{3}\u{2}\u{1}"
Writes the contents of slice, interpreted as a sequence of UTF-8 or ASCII
characters, into this IO
. The contents are transcoded into this IO
's
current encoding.
bytes = "你".to_slice # => Bytes[228, 189, 160]
io = IO::Memory.new
io.set_encoding("GB2312")
io.write_string(bytes)
io.to_slice # => Bytes[196, 227]
"你".encode("GB2312") # => Bytes[196, 227]
Writes the contents of slice, interpreted as a sequence of UTF-8 or ASCII
characters, into this IO
. The contents are transcoded into this IO
's
current encoding.
bytes = "你".to_slice # => Bytes[228, 189, 160]
io = IO::Memory.new
io.set_encoding("GB2312")
io.write_string(bytes)
io.to_slice # => Bytes[196, 227]
"你".encode("GB2312") # => Bytes[196, 227]
DEPRECATED Use #write_string
instead.