An instance of class IO (commonly called a stream) represents an input/output stream in the underlying operating system. Class IO is the basis for input and output in Ruby.
Class File
is the only class in the Ruby core that is a subclass of IO. Some classes in the Ruby standard library are also subclasses of IO; these include TCPSocket
and UDPSocket
.
The global constant ARGF
(also accessible as $<
) provides an IO-like stream that allows access to all file paths found in ARGV (or found in STDIN if ARGV is empty). ARGF
is not itself a subclass of IO.
Class StringIO
provides an IO-like stream that handles a String
. StringIO
is not itself a subclass of IO.
Important objects based on IO include:
-
$stdin.
-
$stdout.
-
$stderr.
-
Instances of class
File
.
An instance of IO may be created using:
-
IO.new
: returns a new IO object for the given integer file descriptor. -
IO.open
: passes a new IO object to the given block. -
IO.popen
: returns a new IO object that is connected to the $stdin and $stdout of a newly-launched subprocess. -
Kernel#open
: Returns a new IO object connected to a given source: stream, file, or subprocess.
Like a File
stream, an IO stream has:
-
A read/write mode, which may be read-only, write-only, or read/write; see Read/Write Mode.
-
A data mode, which may be text-only or binary; see Data Mode.
-
Internal and external encodings; see Encodings.
And like other IO streams, it has:
-
A position, which determines where in the stream the next read or write is to occur; see Position.
-
A line number, which is a special, line-oriented, “position” (different from the position mentioned above); see Line Number.
Extension io/console
Extension io/console
provides numerous methods for interacting with the console; requiring it adds numerous methods to class IO.
Example Files
Many examples here use these variables:
# English text with newlines. text = <<~EOT First line Second line Fourth line Fifth line EOT # Russian text. russian = "\u{442 435 441 442}" # => "тест" # Binary data. data = "\u9990\u9991\u9992\u9993\u9994" # Text file. File.write('t.txt', text) # File with Russian text. File.write('t.rus', russian) # File with binary data. f = File.new('t.dat', 'wb:UTF-16') f.write(data) f.close
Open Options
A number of IO methods accept optional keyword arguments that determine how a new stream is to be opened:
-
:mode
: Stream mode. -
:flags
:Integer
file open flags; Ifmode
is also given, the two are bitwise-ORed. -
:external_encoding
: External encoding for the stream. -
:internal_encoding
: Internal encoding for the stream.'-'
is a synonym for the default internal encoding. If the value isnil
no conversion occurs. -
:encoding
: Specifies external and internal encodings as'extern:intern'
. -
:textmode
: If a truthy value, specifies the mode as text-only, binary otherwise. -
:binmode
: If a truthy value, specifies the mode as binary, text-only otherwise. -
:autoclose
: If a truthy value, specifies that thefd
will close when the stream closes; otherwise it remains open. -
:path:
If a string value is provided, it is used ininspect
and is available aspath
method.
Also available are the options offered in String#encode
, which may control conversion between external and internal encoding.
Basic IO
You can perform basic stream IO with these methods, which typically operate on multi-byte strings:
-
IO#read
: Reads and returns some or all of the remaining bytes from the stream. -
IO#write
: Writes zero or more strings to the stream; each given object that is not already a string is converted viato_s
.
Position
An IO stream has a nonnegative integer position, which is the byte offset at which the next read or write is to occur. A new stream has position zero (and line number zero); method rewind
resets the position (and line number) to zero.
The relevant methods:
-
IO#tell
(aliased as#pos
): Returns the current position (in bytes) in the stream. -
IO#pos=
: Sets the position of the stream to a given integernew_position
(in bytes). -
IO#seek
: Sets the position of the stream to a given integeroffset
(in bytes), relative to a given positionwhence
(indicating the beginning, end, or current position). -
IO#rewind
: Positions the stream at the beginning (also resetting the line number).
Open and Closed Streams
A new IO stream may be open for reading, open for writing, or both.
A stream is automatically closed when claimed by the garbage collector.
Attempted reading or writing on a closed stream raises an exception.
The relevant methods:
-
IO#close
: Closes the stream for both reading and writing. -
IO#close_read
: Closes the stream for reading. -
IO#close_write
: Closes the stream for writing. -
IO#closed?
: Returns whether the stream is closed.
End-of-Stream
You can query whether a stream is positioned at its end:
-
IO#eof?
(also aliased as#eof
): Returns whether the stream is at end-of-stream.
You can reposition to end-of-stream by using method IO#seek
:
f = File.new('t.txt') f.eof? # => false f.seek(0, :END) f.eof? # => true f.close
Or by reading all stream content (which is slower than using IO#seek
):
f.rewind f.eof? # => false f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n" f.eof? # => true
Line IO
You can read an IO stream line-by-line using these methods:
-
IO#each_line
: Reads each remaining line, passing it to the given block. -
IO#gets
: Returns the next line. -
IO#readline
: Likegets
, but raises an exception at end-of-stream. -
IO#readlines
: Returns all remaining lines in an array.
Each of these reader methods accepts:
-
An optional line separator,
sep
; see Line Separator. -
An optional line-size limit,
limit
; see Line Limit.
For each of these reader methods, reading may begin mid-line, depending on the stream’s position; see Position:
f = File.new('t.txt') f.pos = 27 f.each_line {|line| p line } f.close
Output:
"rth line\n" "Fifth line\n"
You can write to an IO stream line-by-line using this method:
-
IO#puts
: Writes objects to the stream.
Line Separator
Each of these methods uses a line separator, which is the string that delimits lines:
The default line separator is the given by the global variable $/
, whose value is by default "\n"
. The line to be read next is all data from the current position to the next line separator:
f = File.new('t.txt') f.gets # => "First line\n" f.gets # => "Second line\n" f.gets # => "\n" f.gets # => "Fourth line\n" f.gets # => "Fifth line\n" f.close
You can specify a different line separator:
f = File.new('t.txt') f.gets('l') # => "First l" f.gets('li') # => "ine\nSecond li" f.gets('lin') # => "ne\n\nFourth lin" f.gets # => "e\n" f.close
There are two special line separators:
-
nil
: The entire stream is read into a single string:f = File.new('t.txt') f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n" f.close
-
''
(the empty string): The next “paragraph” is read (paragraphs being separated by two consecutive line separators):f = File.new('t.txt') f.gets('') # => "First line\nSecond line\n\n" f.gets('') # => "Fourth line\nFifth line\n" f.close
Line Limit
Each of these methods uses a line limit, which specifies that the number of bytes returned may not be (much) longer than the given limit
;
A multi-byte character will not be split, and so a line may be slightly longer than the given limit.
If limit
is not given, the line is determined only by sep
.
# Text with 1-byte characters. File.open('t.txt') {|f| f.gets(1) } # => "F" File.open('t.txt') {|f| f.gets(2) } # => "Fi" File.open('t.txt') {|f| f.gets(3) } # => "Fir" File.open('t.txt') {|f| f.gets(4) } # => "Firs" # No more than one line. File.open('t.txt') {|f| f.gets(10) } # => "First line" File.open('t.txt') {|f| f.gets(11) } # => "First line\n" File.open('t.txt') {|f| f.gets(12) } # => "First line\n" # Text with 2-byte characters, which will not be split. File.open('t.rus') {|f| f.gets(1).size } # => 1 File.open('t.rus') {|f| f.gets(2).size } # => 1 File.open('t.rus') {|f| f.gets(3).size } # => 2 File.open('t.rus') {|f| f.gets(4).size } # => 2
Line Separator and Line Limit
With arguments sep
and limit
given, combines the two behaviors:
-
Returns the next line as determined by line separator
sep
. -
But returns no more bytes than are allowed by the limit.
Example:
File.open('t.txt') {|f| f.gets('li', 20) } # => "First li" File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
Line Number
A readable IO stream has a non-negative integer line number.
The relevant methods:
-
IO#lineno
: Returns the line number. -
IO#lineno=
: Resets and returns the line number.
Unless modified by a call to method IO#lineno=
, the line number is the number of lines read by certain line-oriented methods, according to the given line separator sep
:
-
IO.foreach
: Increments the line number on each call to the block. -
IO#each_line
: Increments the line number on each call to the block. -
IO#gets
: Increments the line number. -
IO#readline
: Increments the line number. -
IO#readlines
: Increments the line number for each line read.
A new stream is initially has line number zero (and position zero); method rewind
resets the line number (and position) to zero:
f = File.new('t.txt') f.lineno # => 0 f.gets # => "First line\n" f.lineno # => 1 f.rewind f.lineno # => 0 f.close
Reading lines from a stream usually changes its line number:
f = File.new('t.txt', 'r') f.lineno # => 0 f.readline # => "This is line one.\n" f.lineno # => 1 f.readline # => "This is the second line.\n" f.lineno # => 2 f.readline # => "Here's the third line.\n" f.lineno # => 3 f.eof? # => true f.close
Iterating over lines in a stream usually changes its line number:
File.open('t.txt') do |f| f.each_line do |line| p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}" end end
Output:
"position=11 eof?=false lineno=1" "position=23 eof?=false lineno=2" "position=24 eof?=false lineno=3" "position=36 eof?=false lineno=4" "position=47 eof?=true lineno=5"
Unlike the stream’s position, the line number does not affect where the next read or write will occur:
f = File.new('t.txt') f.lineno = 1000 f.lineno # => 1000 f.gets # => "First line\n" f.lineno # => 1001 f.close
Associated with the line number is the global variable $.
:
-
When a stream is opened,
$.
is not set; its value is left over from previous activity in the process:$. = 41 f = File.new('t.txt') $. = 41 # => 41 f.close
-
When a stream is read,
$.
is set to the line number for that stream:f0 = File.new('t.txt') f1 = File.new('t.dat') f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"] $. # => 5 f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"] $. # => 1 f0.close f1.close
-
Methods
IO#rewind
andIO#seek
do not affect$.
:f = File.new('t.txt') f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"] $. # => 5 f.rewind f.seek(0, :SET) $. # => 5 f.close
Character IO
You can process an IO stream character-by-character using these methods:
-
IO#getc
: Reads and returns the next character from the stream. -
IO#readchar
: Likegetc
, but raises an exception at end-of-stream. -
IO#ungetc
: Pushes back (“unshifts”) a character or integer onto the stream. -
IO#putc
: Writes a character to the stream. -
IO#each_char
: Reads each remaining character in the stream, passing the character to the given block.
Byte IO
You can process an IO stream byte-by-byte using these methods:
-
IO#getbyte
: Returns the next 8-bit byte as an integer in range 0..255. -
IO#readbyte
: Likegetbyte
, but raises an exception if at end-of-stream. -
IO#ungetbyte
: Pushes back (“unshifts”) a byte back onto the stream. -
IO#each_byte
: Reads each remaining byte in the stream, passing the byte to the given block.
Codepoint IO
You can process an IO stream codepoint-by-codepoint:
-
IO#each_codepoint
: Reads each remaining codepoint, passing it to the given block.
What’s Here
First, what’s elsewhere. Class IO:
-
Inherits from class Object.
-
Includes module Enumerable, which provides dozens of additional methods.
Here, class IO provides methods that are useful for:
Creating
-
::new
(aliased as::for_fd
): Creates and returns a new IO object for the given integer file descriptor. -
::open
: Creates a new IO object. -
::pipe
: Creates a connected pair of reader and writer IO objects. -
::popen
: Creates an IO object to interact with a subprocess. -
::select
: Selects which given IO instances are ready for reading, writing, or have pending exceptions.
Reading
-
::binread
: Returns a binary string with all or a subset of bytes from the given file. -
::read
: Returns a string with all or a subset of bytes from the given file. -
::readlines
: Returns an array of strings, which are the lines from the given file. -
getbyte
: Returns the next 8-bit byte read fromself
as an integer. -
getc
: Returns the next character read fromself
as a string. -
gets
: Returns the line read fromself
. -
pread
: Returns all or the next n bytes read fromself
, not updating the receiver’s offset. -
read
: Returns all remaining or the next n bytes read fromself
for a given n. -
read_nonblock
: the next n bytes read fromself
for a given n, in non-block mode. -
readbyte
: Returns the next byte read fromself
; same asgetbyte
, but raises an exception on end-of-stream. -
readchar
: Returns the next character read fromself
; same asgetc
, but raises an exception on end-of-stream. -
readline
: Returns the next line read fromself
; same as getline, but raises an exception of end-of-stream. -
readlines
: Returns an array of all lines read read fromself
. -
readpartial
: Returns up to the given number of bytes fromself
.
Writing
-
::binwrite
: Writes the given string to the file at the given filepath, in binary mode. -
::write
: Writes the given string toself
. -
<<
: Appends the given string toself
. -
print
: Prints last read line or given objects toself
. -
printf
: Writes toself
based on the given format string and objects. -
putc
: Writes a character toself
. -
puts
: Writes lines toself
, making sure line ends with a newline. -
pwrite
: Writes the given string at the given offset, not updating the receiver’s offset. -
write
: Writes one or more given strings toself
. -
write_nonblock
: Writes one or more given strings toself
in non-blocking mode.
Positioning
-
lineno
: Returns the current line number inself
. -
lineno=
: Sets the line number isself
. -
pos
(aliased astell
): Returns the current byte offset inself
. -
pos=
: Sets the byte offset inself
. -
reopen
: Reassociatesself
with a new or existing IO stream. -
rewind
: Positionsself
to the beginning of input. -
seek
: Sets the offset forself
relative to given position.
Iterating
-
::foreach
: Yields each line of given file to the block. -
each
(aliased aseach_line
): Calls the given block with each successive line inself
. -
each_byte
: Calls the given block with each successive byte inself
as an integer. -
each_char
: Calls the given block with each successive character inself
as a string. -
each_codepoint
: Calls the given block with each successive codepoint inself
as an integer.
Settings
-
autoclose=
: Sets whetherself
auto-closes. -
binmode
: Setsself
to binary mode. -
close
: Closesself
. -
close_on_exec=
: Sets the close-on-exec flag. -
close_read
: Closesself
for reading. -
close_write
: Closesself
for writing. -
set_encoding
: Sets the encoding forself
. -
set_encoding_by_bom
: Sets the encoding forself
, based on its Unicode byte-order-mark. -
sync=
: Sets the sync-mode to the given value.
Querying
-
autoclose?
: Returns whetherself
auto-closes. -
binmode?
: Returns whetherself
is in binary mode. -
close_on_exec?
: Returns the close-on-exec flag forself
. -
closed?
: Returns whetherself
is closed. -
eof?
(aliased aseof
): Returns whetherself
is at end-of-stream. -
external_encoding
: Returns the external encoding object forself
. -
fileno
(aliased asto_i
): Returns the integer file descriptor forself
-
internal_encoding
: Returns the internal encoding object forself
. -
pid
: Returns the process ID of a child process associated withself
, ifself
was created by::popen
. -
stat
: Returns theFile::Stat
object containing status information forself
. -
sync
: Returns whetherself
is in sync-mode. -
tty?
(aliased asisatty
): Returns whetherself
is a terminal.
Buffering
-
fdatasync
: Immediately writes all buffered data inself
to disk. -
flush
: Flushes any buffered data withinself
to the underlying operating system. -
fsync
: Immediately writes all buffered data and attributes inself
to disk. -
ungetbyte
: Prepends buffer forself
with given integer byte or string. -
ungetc
: Prepends buffer forself
with given string.
Low-Level Access
-
::sysopen
: Opens the file given by its path, returning the integer file descriptor. -
advise
: Announces the intention to access data fromself
in a specific way. -
fcntl
: Passes a low-level command to the file specified by the given file descriptor. -
ioctl
: Passes a low-level command to the device specified by the given file descriptor. -
sysread
: Returns up to the next n bytes read from self using a low-level read. -
sysseek
: Sets the offset forself
. -
syswrite
: Writes the given string toself
using a low-level write.
Other
-
::copy_stream
: Copies data from a source to a destination, each of which is a filepath or an IO-like object. -
::try_convert
: Returns a new IO object resulting from converting the given object. -
inspect
: Returns the string representation ofself
.
static VALUE
rb_io_s_binread(int argc, VALUE *argv, VALUE io)
{
VALUE offset;
struct foreach_arg arg;
enum {
fmode = FMODE_READABLE|FMODE_BINMODE,
oflags = O_RDONLY
#ifdef O_BINARY
|O_BINARY
#endif
};
struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
FilePathValue(argv[0]);
convconfig.enc = rb_ascii8bit_encoding();
arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
if (NIL_P(arg.io)) return Qnil;
arg.argv = argv+1;
arg.argc = (argc > 1) ? 1 : 0;
if (!NIL_P(offset)) {
struct seek_arg sarg;
int state = 0;
sarg.io = arg.io;
sarg.offset = offset;
sarg.mode = SEEK_SET;
rb_protect(seek_before_access, (VALUE)&sarg, &state);
if (state) {
rb_io_close(arg.io);
rb_jump_tag(state);
}
}
return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
}
Behaves like IO.read
, except that the stream is opened in binary mode with ASCII-8BIT encoding.
When called from class IO (but not subclasses of IO), this method has potential security vulnerabilities if called with untrusted input; see Command Injection.
static VALUE
rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
{
return io_s_write(argc, argv, io, 1);
}
Behaves like IO.write
, except that the stream is opened in binary mode with ASCII-8BIT encoding.
When called from class IO (but not subclasses of IO), this method has potential security vulnerabilities if called with untrusted input; see Command Injection.
static VALUE
console_dev(int argc, VALUE *argv, VALUE klass)
{
VALUE con = 0;
VALUE sym = 0;
rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
if (argc) {
Check_Type(sym = argv[0], T_SYMBOL);
}
// Force the class to be File.
if (klass == rb_cIO) klass = rb_cFile;
if (rb_const_defined(klass, id_console)) {
con = rb_const_get(klass, id_console);
if (!RB_TYPE_P(con, T_FILE) || RTEST(rb_io_closed_p(con))) {
rb_const_remove(klass, id_console);
con = 0;
}
}
if (sym) {
if (sym == ID2SYM(id_close) && argc == 1) {
if (con) {
rb_io_close(con);
rb_const_remove(klass, id_console);
con = 0;
}
return Qnil;
}
}
if (!con) {
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
# define CONSOLE_DEVICE "/dev/tty"
#elif defined _WIN32
# define CONSOLE_DEVICE "con$"
# define CONSOLE_DEVICE_FOR_READING "conin$"
# define CONSOLE_DEVICE_FOR_WRITING "conout$"
#endif
#ifndef CONSOLE_DEVICE_FOR_READING
# define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE
#endif
#ifdef CONSOLE_DEVICE_FOR_WRITING
VALUE out;
rb_io_t *ofptr;
#endif
int fd;
VALUE path = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
#ifdef CONSOLE_DEVICE_FOR_WRITING
fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
if (fd < 0) return Qnil;
out = rb_io_open_descriptor(klass, fd, FMODE_WRITABLE | FMODE_SYNC, path, Qnil, NULL);
#endif
fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0);
if (fd < 0) {
#ifdef CONSOLE_DEVICE_FOR_WRITING
rb_io_close(out);
#endif
return Qnil;
}
con = rb_io_open_descriptor(klass, fd, FMODE_READWRITE | FMODE_SYNC, path, Qnil, NULL);
#ifdef CONSOLE_DEVICE_FOR_WRITING
rb_io_set_write_io(con, out);
#endif
rb_const_set(klass, id_console, con);
}
if (sym) {
return rb_f_send(argc, argv, con);
}
return con;
}
static VALUE
rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
{
VALUE src, dst, length, src_offset;
struct copy_stream_struct st;
MEMZERO(&st, struct copy_stream_struct, 1);
rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
st.src = src;
st.dst = dst;
st.src_fptr = NULL;
st.dst_fptr = NULL;
if (NIL_P(length))
st.copy_length = (rb_off_t)-1;
else
st.copy_length = NUM2OFFT(length);
if (NIL_P(src_offset))
st.src_offset = (rb_off_t)-1;
else
st.src_offset = NUM2OFFT(src_offset);
rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
return OFFT2NUM(st.total);
}
Copies from the given src
to the given dst
, returning the number of bytes copied.
-
The given
src
must be one of the following:-
The path to a readable file, from which source data is to be read.
-
An IO-like object, opened for reading and capable of responding to method
:readpartial
or method:read
.
-
-
The given
dst
must be one of the following:-
The path to a writable file, to which data is to be written.
-
An IO-like object, opened for writing and capable of responding to method
:write
.
-
The examples here use file t.txt
as source:
File.read('t.txt') # => "First line\nSecond line\n\nThird line\nFourth line\n" File.read('t.txt').size # => 47
If only arguments src
and dst
are given, the entire source stream is copied:
# Paths. IO.copy_stream('t.txt', 't.tmp') # => 47 # IOs (recall that a File is also an IO). src_io = File.open('t.txt', 'r') # => #<File:t.txt> dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp> IO.copy_stream(src_io, dst_io) # => 47 src_io.close dst_io.close
With argument src_length
a non-negative integer, no more than that many bytes are copied:
IO.copy_stream('t.txt', 't.tmp', 10) # => 10 File.read('t.tmp') # => "First line"
With argument src_offset
also given, the source stream is read beginning at that offset:
IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11 IO.read('t.tmp') # => "Second line"
static VALUE
rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
{
VALUE io = rb_obj_alloc(klass);
rb_io_initialize(argc, argv, io);
return io;
}
Synonym for IO.new
.
static VALUE
rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
{
VALUE opt;
int orig_argc = argc;
struct foreach_arg arg;
struct getline_arg garg;
argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
RETURN_ENUMERATOR(self, orig_argc, argv);
extract_getline_args(argc-1, argv+1, &garg);
open_key_args(self, argc, argv, opt, &arg);
if (NIL_P(arg.io)) return Qnil;
extract_getline_opts(opt, &garg);
check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
}
Calls the block with each successive line read from the stream.
When called from class IO (but not subclasses of IO), this method has potential security vulnerabilities if called with untrusted input; see Command Injection.
The first argument must be a string that is the path to a file.
With only argument path
given, parses lines from the file at the given path
, as determined by the default line separator, and calls the block with each successive line:
File.foreach('t.txt') {|line| p line }
Output: the same as above.
For both forms, command and path, the remaining arguments are the same.
With argument sep
given, parses lines as determined by that line separator (see Line Separator):
File.foreach('t.txt', 'li') {|line| p line }
Output:
"First li" "ne\nSecond li" "ne\n\nThird li" "ne\nFourth li" "ne\n"
Each paragraph:
File.foreach('t.txt', '') {|paragraph| p paragraph }
Output:
"First line\nSecond line\n\n" "Third line\nFourth line\n"
With argument limit
given, parses lines as determined by the default line separator and the given line-length limit (see Line Limit):
File.foreach('t.txt', 7) {|line| p line }
Output:
"First l" "ine\n" "Second " "line\n" "\n" "Third l" "ine\n" "Fourth l" "line\n"
With arguments sep
and limit
given, parses lines as determined by the given line separator and the given line-length limit (see Line Separator and Line Limit):
Optional keyword arguments opts
specify:
-
Encoding options.
Returns an Enumerator
if no block is given.
static VALUE
rb_io_initialize(int argc, VALUE *argv, VALUE io)
{
VALUE fnum, vmode;
rb_io_t *fp;
int fd, fmode, oflags = O_RDONLY;
struct rb_io_encoding convconfig;
VALUE opt;
#if defined(HAVE_FCNTL) && defined(F_GETFL)
int ofmode;
#else
struct stat st;
#endif
argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
fd = NUM2INT(fnum);
if (rb_reserved_fd_p(fd)) {
rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
}
#if defined(HAVE_FCNTL) && defined(F_GETFL)
oflags = fcntl(fd, F_GETFL);
if (oflags == -1) rb_sys_fail(0);
#else
if (fstat(fd, &st) < 0) rb_sys_fail(0);
#endif
rb_update_max_fd(fd);
#if defined(HAVE_FCNTL) && defined(F_GETFL)
ofmode = rb_io_oflags_fmode(oflags);
if (NIL_P(vmode)) {
fmode = ofmode;
}
else if ((~ofmode & fmode) & FMODE_READWRITE) {
VALUE error = INT2FIX(EINVAL);
rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
}
#endif
VALUE path = Qnil;
if (!NIL_P(opt)) {
if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
fmode |= FMODE_EXTERNAL;
}
path = rb_hash_aref(opt, RB_ID2SYM(idPath));
if (!NIL_P(path)) {
StringValue(path);
path = rb_str_new_frozen(path);
}
}
MakeOpenFile(io, fp);
fp->self = io;
fp->fd = fd;
fp->mode = fmode;
fp->encs = convconfig;
fp->pathv = path;
fp->timeout = Qnil;
clear_codeconv(fp);
io_check_tty(fp);
if (fileno(stdin) == fd)
fp->stdio_file = stdin;
else if (fileno(stdout) == fd)
fp->stdio_file = stdout;
else if (fileno(stderr) == fd)
fp->stdio_file = stderr;
if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
return io;
}
Creates and returns a new IO object (file stream) from a file descriptor.
IO.new may be useful for interaction with low-level libraries. For higher-level interactions, it may be simpler to create the file stream using File.open
.
Argument fd
must be a valid file descriptor (integer):
path = 't.tmp' fd = IO.sysopen(path) # => 3 IO.new(fd) # => #<IO:fd 3>
The new IO object does not inherit encoding (because the integer file descriptor does not have an encoding):
fd = IO.sysopen('t.rus', 'rb') io = IO.new(fd) io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
Optional argument mode
(defaults to ‘r’) must specify a valid mode; see Access Modes:
IO.new(fd, 'w') # => #<IO:fd 3> IO.new(fd, File::WRONLY) # => #<IO:fd 3>
Optional keyword arguments opts
specify:
-
Encoding options.
Examples:
IO.new(fd, internal_encoding: nil) # => #<IO:fd 3> IO.new(fd, autoclose: true) # => #<IO:fd 3>
static VALUE
rb_io_s_open(int argc, VALUE *argv, VALUE klass)
{
VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
if (rb_block_given_p()) {
return rb_ensure(rb_yield, io, io_close, io);
}
return io;
}
Creates a new IO object, via IO.new
with the given arguments.
With no block given, returns the IO object.
With a block given, calls the block with the IO object and returns the block’s value.
static VALUE
rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
{
int pipes[2], state;
VALUE r, w, args[3], v1, v2;
VALUE opt;
rb_io_t *fptr, *fptr2;
struct io_encoding_set_args ies_args;
int fmode = 0;
VALUE ret;
argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
if (rb_pipe(pipes) < 0)
rb_sys_fail(0);
args[0] = klass;
args[1] = INT2NUM(pipes[0]);
args[2] = INT2FIX(O_RDONLY);
r = rb_protect(io_new_instance, (VALUE)args, &state);
if (state) {
close(pipes[0]);
close(pipes[1]);
rb_jump_tag(state);
}
GetOpenFile(r, fptr);
ies_args.fptr = fptr;
ies_args.v1 = v1;
ies_args.v2 = v2;
ies_args.opt = opt;
rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
if (state) {
close(pipes[1]);
io_close(r);
rb_jump_tag(state);
}
args[1] = INT2NUM(pipes[1]);
args[2] = INT2FIX(O_WRONLY);
w = rb_protect(io_new_instance, (VALUE)args, &state);
if (state) {
close(pipes[1]);
if (!NIL_P(r)) rb_io_close(r);
rb_jump_tag(state);
}
GetOpenFile(w, fptr2);
rb_io_synchronized(fptr2);
extract_binmode(opt, &fmode);
if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
rb_io_ascii8bit_binmode(r);
rb_io_ascii8bit_binmode(w);
}
#if DEFAULT_TEXTMODE
if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
fptr->mode &= ~FMODE_TEXTMODE;
setmode(fptr->fd, O_BINARY);
}
#if RUBY_CRLF_ENVIRONMENT
if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
}
#endif
#endif
fptr->mode |= fmode;
#if DEFAULT_TEXTMODE
if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
fptr2->mode &= ~FMODE_TEXTMODE;
setmode(fptr2->fd, O_BINARY);
}
#endif
fptr2->mode |= fmode;
ret = rb_assoc_new(r, w);
if (rb_block_given_p()) {
VALUE rw[2];
rw[0] = r;
rw[1] = w;
return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
}
return ret;
}
Creates a pair of pipe endpoints, read_io
and write_io
, connected to each other.
If argument enc_string
is given, it must be a string containing one of:
-
The name of the encoding to be used as the external encoding.
-
The colon-separated names of two encodings to be used as the external and internal encodings.
If argument int_enc
is given, it must be an Encoding
object or encoding name string that specifies the internal encoding to be used; if argument ext_enc
is also given, it must be an Encoding
object or encoding name string that specifies the external encoding to be used.
The string read from read_io
is tagged with the external encoding; if an internal encoding is also specified, the string is converted to, and tagged with, that encoding.
If any encoding is specified, optional hash arguments specify the conversion option.
Optional keyword arguments opts
specify:
-
Encoding Options.
With no block given, returns the two endpoints in an array:
IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
With a block given, calls the block with the two endpoints; closes both endpoints and returns the value of the block:
IO.pipe {|read_io, write_io| p read_io; p write_io }
Output:
#<IO:fd 6> #<IO:fd 7>
Not available on all platforms.
In the example below, the two processes close the ends of the pipe that they are not using. This is not just a cosmetic nicety. The read end of a pipe will not generate an end of file condition if there are any writers with the pipe still open. In the case of the parent process, the rd.read
will never return if it does not first issue a wr.close
:
rd, wr = IO.pipe if fork wr.close puts "Parent got: <#{rd.read}>" rd.close Process.wait else rd.close puts 'Sending message to parent' wr.write "Hi Dad" wr.close end
produces:
Sending message to parent Parent got: <Hi Dad>
static VALUE
rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
{
VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
switch (argc) {
case 2:
pmode = argv[1];
case 1:
pname = argv[0];
break;
default:
{
int ex = !NIL_P(opt);
rb_error_arity(argc + ex, 1 + ex, 2 + ex);
}
}
return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
}
Executes the given command cmd
as a subprocess whose $stdin and $stdout are connected to a new stream io
.
This method has potential security vulnerabilities if called with untrusted input; see Command Injection.
If no block is given, returns the new stream, which depending on given mode
may be open for reading, writing, or both. The stream should be explicitly closed (eventually) to avoid resource leaks.
If a block is given, the stream is passed to the block (again, open for reading, writing, or both); when the block exits, the stream is closed, and the block’s value is assigned to global variable $?
and returned.
Optional argument mode
may be any valid IO mode. See Access Modes.
Required argument cmd
determines which of the following occurs:
-
The process forks.
-
A specified program runs in a shell.
-
A specified program runs with specified arguments.
-
A specified program runs with specified arguments and a specified
argv0
.
Each of these is detailed below.
The optional hash argument env
specifies name/value pairs that are to be added to the environment variables for the subprocess:
IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe| pipe.puts 'puts ENV["FOO"]' pipe.close_write pipe.gets end => "bar\n"
Optional keyword arguments opts
specify:
-
Encoding options.
-
Options for
Kernel#spawn
.
Forked Process
When argument cmd
is the 1-character string '-'
, causes the process to fork:
IO.popen('-') do |pipe| if pipe $stderr.puts "In parent, child pid is #{pipe.pid}\n" else $stderr.puts "In child, pid is #{$$}\n" end end
Output:
In parent, child pid is 26253 In child, pid is 26253
Note that this is not supported on all platforms.
Shell Subprocess
When argument cmd
is a single string (but not '-'
), the program named cmd
is run as a shell command:
IO.popen('uname') do |pipe| pipe.readlines end
Output:
["Linux\n"]
Another example:
IO.popen('/bin/sh', 'r+') do |pipe| pipe.puts('ls') pipe.close_write $stderr.puts pipe.readlines.size end
Output:
213
Program Subprocess
When argument cmd
is an array of strings, the program named cmd[0]
is run with all elements of cmd
as its arguments:
IO.popen(['du', '..', '.']) do |pipe| $stderr.puts pipe.readlines.size end
Output:
1111
Program Subprocess with argv0
When argument cmd
is an array whose first element is a 2-element string array and whose remaining elements (if any) are strings:
-
cmd[0][0]
(the first string in the nested array) is the name of a program that is run. -
cmd[0][1]
(the second string in the nested array) is set as the program’sargv[0]
. -
cmd[1..-1]
(the strings in the outer array) are the program’s arguments.
Example (sets $0
to ‘foo’):
IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
Some Special Examples
# Set IO encoding. IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io| euc_jp_string = nkf_io.read } # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn. IO.popen(["ls", "/", :err=>[:child, :out]]) do |io| ls_result_with_error = io.read end # Use mixture of spawn options and IO options. IO.popen(["ls", "/"], :err=>[:child, :out]) do |io| ls_result_with_error = io.read end f = IO.popen("uname") p f.readlines f.close puts "Parent is #{Process.pid}" IO.popen("date") {|f| puts f.gets } IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"} p $? IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f| f.puts "bar"; f.close_write; puts f.gets }
Output (from last section):
["Linux\n"] Parent is 21346 Thu Jan 15 22:41:19 JST 2009 21346 is here, f is #<IO:fd 3> 21352 is here, f is nil #<Process::Status: pid 21352 exit 0> <foo>bar;zot;
Raises exceptions that IO.pipe
and Kernel.spawn
raise.
static VALUE
rb_io_s_read(int argc, VALUE *argv, VALUE io)
{
VALUE opt, offset;
long off;
struct foreach_arg arg;
argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
rb_raise(rb_eArgError, "negative offset %ld given", off);
}
open_key_args(io, argc, argv, opt, &arg);
if (NIL_P(arg.io)) return Qnil;
if (!NIL_P(offset)) {
struct seek_arg sarg;
int state = 0;
sarg.io = arg.io;
sarg.offset = offset;
sarg.mode = SEEK_SET;
rb_protect(seek_before_access, (VALUE)&sarg, &state);
if (state) {
rb_io_close(arg.io);
rb_jump_tag(state);
}
if (arg.argc == 2) arg.argc = 1;
}
return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
}
Opens the stream, reads and returns some or all of its content, and closes the stream; returns nil
if no bytes were read.
When called from class IO (but not subclasses of IO), this method has potential security vulnerabilities if called with untrusted input; see Command Injection.
The first argument must be a string that is the path to a file.
With only argument path
given, reads in text mode and returns the entire content of the file at the given path:
IO.read('t.txt') # => "First line\nSecond line\n\nThird line\nFourth line\n"
On Windows, text mode can terminate reading and leave bytes in the file unread when encountering certain special bytes. Consider using IO.binread
if all bytes in the file should be read.
With argument length
, returns length
bytes if available:
IO.read('t.txt', 7) # => "First l" IO.read('t.txt', 700) # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
With arguments length
and offset
, returns length
bytes if available, beginning at the given offset
:
IO.read('t.txt', 10, 2) # => "rst line\nS" IO.read('t.txt', 10, 200) # => nil
Optional keyword arguments opts
specify:
-
Encoding options.
static VALUE
rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
{
VALUE opt;
struct foreach_arg arg;
struct getline_arg garg;
argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
extract_getline_args(argc-1, argv+1, &garg);
open_key_args(io, argc, argv, opt, &arg);
if (NIL_P(arg.io)) return Qnil;
extract_getline_opts(opt, &garg);
check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
}
Returns an array of all lines read from the stream.
When called from class IO (but not subclasses of IO), this method has potential security vulnerabilities if called with untrusted input; see Command Injection.
The first argument must be a string that is the path to a file.
With only argument path
given, parses lines from the file at the given path
, as determined by the default line separator, and returns those lines in an array:
IO.readlines('t.txt') # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
With argument sep
given, parses lines as determined by that line separator (see Line Separator):
# Ordinary separator. IO.readlines('t.txt', 'li') # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"] # Get-paragraphs separator. IO.readlines('t.txt', '') # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"] # Get-all separator. IO.readlines('t.txt', nil) # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
With argument limit
given, parses lines as determined by the default line separator and the given line-length limit (see Line Limit):
IO.readlines('t.txt', 7) # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
With arguments sep
and limit
given, parses lines as determined by the given line separator and the given line-length limit (see Line Separator and Line Limit):
Optional keyword arguments opts
specify:
-
Encoding options.
static VALUE
rb_f_select(int argc, VALUE *argv, VALUE obj)
{
VALUE scheduler = rb_fiber_scheduler_current();
if (scheduler != Qnil) {
// It's optionally supported.
VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
if (!UNDEF_P(result)) return result;
}
VALUE timeout;
struct select_args args;
struct timeval timerec;
int i;
rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
if (NIL_P(timeout)) {
args.timeout = 0;
}
else {
timerec = rb_time_interval(timeout);
args.timeout = &timerec;
}
for (i = 0; i < numberof(args.fdsets); ++i)
rb_fd_init(&args.fdsets[i]);
return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
}
Invokes system call select(2), which monitors multiple file descriptors, waiting until one or more of the file descriptors becomes ready for some class of I/O operation.
Not implemented on all platforms.
Each of the arguments read_ios
, write_ios
, and error_ios
is an array of IO
objects.
Argument timeout
is an integer timeout interval in seconds.
The method monitors the IO objects given in all three arrays, waiting for some to be ready; returns a 3-element array whose elements are:
-
An array of the objects in
read_ios
that are ready for reading. -
An array of the objects in
write_ios
that are ready for writing. -
An array of the objects in
error_ios
have pending exceptions.
If no object becomes ready within the given timeout
, nil
is returned.
IO.select peeks the buffer of IO objects for testing readability. If the IO buffer is not empty, IO.select immediately notifies readability. This “peek” only happens for IO objects. It does not happen for IO-like objects such as OpenSSL::SSL::SSLSocket
.
The best way to use IO.select is invoking it after non-blocking methods such as read_nonblock
, write_nonblock
, etc. The methods raise an exception which is extended by IO::WaitReadable
or IO::WaitWritable
. The modules notify how the caller should wait with IO.select. If IO::WaitReadable
is raised, the caller should wait for reading. If IO::WaitWritable
is raised, the caller should wait for writing.
So, blocking read (readpartial
) can be emulated using read_nonblock
and IO.select as follows:
begin result = io_like.read_nonblock(maxlen) rescue IO::WaitReadable IO.select([io_like]) retry rescue IO::WaitWritable IO.select(nil, [io_like]) retry end
Especially, the combination of non-blocking methods and IO.select is preferred for IO
like objects such as OpenSSL::SSL::SSLSocket
. It has to_io
method to return underlying IO
object. IO.select
calls to_io
to obtain the file descriptor to wait.
This means that readability notified by IO.select doesn’t mean readability from OpenSSL::SSL::SSLSocket
object.
The most likely situation is that OpenSSL::SSL::SSLSocket
buffers some data. IO.select doesn’t see the buffer. So IO.select can block when OpenSSL::SSL::SSLSocket#readpartial
doesn’t block.
However, several more complicated situations exist.
SSL is a protocol which is sequence of records. The record consists of multiple bytes. So, the remote side of SSL sends a partial record, IO.select
notifies readability but OpenSSL::SSL::SSLSocket
cannot decrypt a byte and OpenSSL::SSL::SSLSocket#readpartial
will block.
Also, the remote side can request SSL renegotiation which forces the local SSL engine to write some data. This means OpenSSL::SSL::SSLSocket#readpartial
may invoke write
system call and it can block. In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock
raises IO::WaitWritable
instead of blocking. So, the caller should wait for ready for writability as above example.
The combination of non-blocking methods and IO.select is also useful for streams such as tty, pipe socket socket when multiple processes read from a stream.
Finally, Linux kernel developers don’t guarantee that readability of select(2) means readability of following read(2) even for a single process; see select(2)
Invoking IO.select before IO#readpartial
works well as usual. However it is not the best way to use IO.select.
The writability notified by select(2) doesn’t show how many bytes are writable. IO#write
method blocks until given whole string is written. So, IO#write(two or more bytes)
can block after writability is notified by IO.select. IO#write_nonblock
is required to avoid the blocking.
Blocking write (write
) can be emulated using write_nonblock
and IO.select
as follows: IO::WaitReadable
should also be rescued for SSL renegotiation in OpenSSL::SSL::SSLSocket
.
while 0 < string.bytesize begin written = io_like.write_nonblock(string) rescue IO::WaitReadable IO.select([io_like]) retry rescue IO::WaitWritable IO.select(nil, [io_like]) retry end string = string.byteslice(written..-1) end
Example:
rp, wp = IO.pipe mesg = "ping " 100.times { # IO.select follows IO#read. Not the best way to use IO.select. rs, ws, = IO.select([rp], [wp]) if r = rs[0] ret = r.read(5) print ret case ret when /ping/ mesg = "pong\n" when /pong/ mesg = "ping " end end if w = ws[0] w.write(mesg) end }
Output:
ping pong ping pong ping pong (snipped) ping
static VALUE
rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
{
VALUE fname, vmode, vperm;
VALUE intmode;
int oflags, fd;
mode_t perm;
rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
FilePathValue(fname);
if (NIL_P(vmode))
oflags = O_RDONLY;
else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
oflags = NUM2INT(intmode);
else {
SafeStringValue(vmode);
oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
}
if (NIL_P(vperm)) perm = 0666;
else perm = NUM2MODET(vperm);
RB_GC_GUARD(fname) = rb_str_new4(fname);
fd = rb_sysopen(fname, oflags, perm);
return INT2NUM(fd);
}
Opens the file at the given path with the given mode and permissions; returns the integer file descriptor.
If the file is to be readable, it must exist; if the file is to be writable and does not exist, it is created with the given permissions:
File.write('t.tmp', '') # => 0 IO.sysopen('t.tmp') # => 8 IO.sysopen('t.tmp', 'w') # => 9
static VALUE
rb_io_s_try_convert(VALUE dummy, VALUE io)
{
return rb_io_check_io(io);
}
Attempts to convert object
into an IO object via method to_io
; returns the new IO object if successful, or nil
otherwise:
IO.try_convert(STDOUT) # => #<IO:<STDOUT>> IO.try_convert(ARGF) # => #<IO:<STDIN>> IO.try_convert('STDOUT') # => nil
static VALUE
rb_io_s_write(int argc, VALUE *argv, VALUE io)
{
return io_s_write(argc, argv, io, 0);
}
Opens the stream, writes the given data
to it, and closes the stream; returns the number of bytes written.
When called from class IO (but not subclasses of IO), this method has potential security vulnerabilities if called with untrusted input; see Command Injection.
The first argument must be a string that is the path to a file.
With only argument path
given, writes the given data
to the file at that path:
IO.write('t.tmp', 'abc') # => 3 File.read('t.tmp') # => "abc"
If offset
is zero (the default), the file is overwritten:
IO.write('t.tmp', 'A') # => 1 File.read('t.tmp') # => "A"
If offset
in within the file content, the file is partly overwritten:
IO.write('t.tmp', 'abcdef') # => 3 File.read('t.tmp') # => "abcdef" # Offset within content. IO.write('t.tmp', '012', 2) # => 3 File.read('t.tmp') # => "ab012f"
If offset
is outside the file content, the file is padded with null characters "\u0000"
:
IO.write('t.tmp', 'xyz', 10) # => 3 File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
Optional keyword arguments opts
specify:
-
Encoding options.
VALUE
rb_io_addstr(VALUE io, VALUE str)
{
rb_io_write(io, str);
return io;
}
Writes the given object
to self
, which must be opened for writing (see Access Modes); returns self
; if object
is not a string, it is converted via method to_s
:
$stdout << 'Hello' << ', ' << 'World!' << "\n" $stdout << 'foo' << :bar << 2 << "\n"
Output:
Hello, World! foobar2
static VALUE
rb_io_advise(int argc, VALUE *argv, VALUE io)
{
VALUE advice, offset, len;
rb_off_t off, l;
rb_io_t *fptr;
rb_scan_args(argc, argv, "12", &advice, &offset, &len);
advice_arg_check(advice);
io = GetWriteIO(io);
GetOpenFile(io, fptr);
off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
l = NIL_P(len) ? 0 : NUM2OFFT(len);
#ifdef HAVE_POSIX_FADVISE
return do_io_advise(fptr, advice, off, l);
#else
((void)off, (void)l); /* Ignore all hint */
return Qnil;
#endif
}
Invokes Posix system call posix_fadvise(2), which announces an intention to access data from the current file in a particular manner.
The arguments and results are platform-dependent.
The relevant data is specified by:
-
offset
: The offset of the first byte of data. -
len
: The number of bytes to be accessed; iflen
is zero, or is larger than the number of bytes remaining, all remaining bytes will be accessed.
Argument advice
is one of the following symbols:
-
:normal
: The application has no advice to give about its access pattern for the specified data. If no advice is given for an open file, this is the default assumption. -
:sequential
: The application expects to access the specified data sequentially (with lower offsets read before higher ones). -
:random
: The specified data will be accessed in random order. -
:noreuse
: The specified data will be accessed only once. -
:willneed
: The specified data will be accessed in the near future. -
:dontneed
: The specified data will not be accessed in the near future.
Not implemented on all platforms.
static VALUE
rb_io_set_autoclose(VALUE io, VALUE autoclose)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
if (!RTEST(autoclose))
fptr->mode |= FMODE_EXTERNAL;
else
fptr->mode &= ~FMODE_EXTERNAL;
return autoclose;
}
Sets auto-close flag.
f = File.open(File::NULL) IO.for_fd(f.fileno).close f.gets # raises Errno::EBADF f = File.open(File::NULL) g = IO.for_fd(f.fileno) g.autoclose = false g.close f.gets # won't cause Errno::EBADF
static VALUE
rb_io_autoclose_p(VALUE io)
{
rb_io_t *fptr = RFILE(io)->fptr;
rb_io_check_closed(fptr);
return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
}
Returns true
if the underlying file descriptor of ios will be closed at its finalization or at calling close
, otherwise false
.
static VALUE
console_beep(VALUE io)
{
#ifdef _WIN32
MessageBeep(0);
#else
int fd = GetWriteFD(io);
if (write(fd, "\a", 1) < 0) sys_fail(io);
#endif
return io;
}
static VALUE
rb_io_binmode_m(VALUE io)
{
VALUE write_io;
rb_io_ascii8bit_binmode(io);
write_io = GetWriteIO(io);
if (write_io != io)
rb_io_ascii8bit_binmode(write_io);
return io;
}
Sets the stream’s data mode as binary (see Data Mode).
A stream’s data mode may not be changed from binary to text.
static VALUE
rb_io_binmode_p(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
return RBOOL(fptr->mode & FMODE_BINMODE);
}
Returns true
if the stream is on binary mode, false
otherwise. See Data Mode.
_WIN32
static VALUE
console_check_winsize_changed(VALUE io)
{
HANDLE h;
DWORD num;
h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(io));
while (GetNumberOfConsoleInputEvents(h, &num) && num > 0) {
INPUT_RECORD rec;
if (ReadConsoleInput(h, &rec, 1, &num)) {
if (rec.EventType == WINDOW_BUFFER_SIZE_EVENT) {
rb_yield(Qnil);
}
}
}
return io;
}
static VALUE
console_clear_screen(VALUE io)
{
console_erase_screen(io, INT2FIX(2));
console_goto(io, INT2FIX(0), INT2FIX(0));
return io;
}
static VALUE
rb_io_close_m(VALUE io)
{
rb_io_t *fptr = rb_io_get_fptr(io);
if (fptr->fd < 0) {
return Qnil;
}
rb_io_close(io);
return Qnil;
}
Closes the stream for both reading and writing if open for either or both; returns nil
. See Open and Closed Streams.
If the stream is open for writing, flushes any buffered writes to the operating system before closing.
If the stream was opened by IO.popen
, sets global variable $?
(child exit status).
Example:
IO.popen('ruby', 'r+') do |pipe| puts pipe.closed? pipe.close puts $? puts pipe.closed? end
Output:
false pid 13760 exit 0 true
Related: IO#close_read
, IO#close_write
, IO#closed?
.
static VALUE
rb_io_set_close_on_exec(VALUE io, VALUE arg)
{
int flag = RTEST(arg) ? FD_CLOEXEC : 0;
rb_io_t *fptr;
VALUE write_io;
int fd, ret;
write_io = GetWriteIO(io);
if (io != write_io) {
GetOpenFile(write_io, fptr);
if (fptr && 0 <= (fd = fptr->fd)) {
if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
if ((ret & FD_CLOEXEC) != flag) {
ret = (ret & ~FD_CLOEXEC) | flag;
ret = fcntl(fd, F_SETFD, ret);
if (ret != 0) rb_sys_fail_path(fptr->pathv);
}
}
}
GetOpenFile(io, fptr);
if (fptr && 0 <= (fd = fptr->fd)) {
if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
if ((ret & FD_CLOEXEC) != flag) {
ret = (ret & ~FD_CLOEXEC) | flag;
ret = fcntl(fd, F_SETFD, ret);
if (ret != 0) rb_sys_fail_path(fptr->pathv);
}
}
return Qnil;
}
Sets a close-on-exec flag.
f = File.open(File::NULL) f.close_on_exec = true system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory f.closed? #=> false
Ruby sets close-on-exec flags of all file descriptors by default since Ruby 2.0.0. So you don’t need to set by yourself. Also, unsetting a close-on-exec flag can cause file descriptor leak if another thread use fork() and exec() (via system() method for example). If you really needs file descriptor inheritance to child process, use spawn()‘s argument such as fd=>fd.
static VALUE
rb_io_close_on_exec_p(VALUE io)
{
rb_io_t *fptr;
VALUE write_io;
int fd, ret;
write_io = GetWriteIO(io);
if (io != write_io) {
GetOpenFile(write_io, fptr);
if (fptr && 0 <= (fd = fptr->fd)) {
if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
if (!(ret & FD_CLOEXEC)) return Qfalse;
}
}
GetOpenFile(io, fptr);
if (fptr && 0 <= (fd = fptr->fd)) {
if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
if (!(ret & FD_CLOEXEC)) return Qfalse;
}
return Qtrue;
}
Returns true
if the stream will be closed on exec, false
otherwise:
f = File.open('t.txt') f.close_on_exec? # => true f.close_on_exec = false f.close_on_exec? # => false f.close
static VALUE
rb_io_close_read(VALUE io)
{
rb_io_t *fptr;
VALUE write_io;
fptr = rb_io_get_fptr(rb_io_taint_check(io));
if (fptr->fd < 0) return Qnil;
if (is_socket(fptr->fd, fptr->pathv)) {
#ifndef SHUT_RD
# define SHUT_RD 0
#endif
if (shutdown(fptr->fd, SHUT_RD) < 0)
rb_sys_fail_path(fptr->pathv);
fptr->mode &= ~FMODE_READABLE;
if (!(fptr->mode & FMODE_WRITABLE))
return rb_io_close(io);
return Qnil;
}
write_io = GetWriteIO(io);
if (io != write_io) {
rb_io_t *wfptr;
wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
wfptr->pid = fptr->pid;
fptr->pid = 0;
RFILE(io)->fptr = wfptr;
/* bind to write_io temporarily to get rid of memory/fd leak */
fptr->tied_io_for_writing = 0;
RFILE(write_io)->fptr = fptr;
rb_io_fptr_cleanup(fptr, FALSE);
/* should not finalize fptr because another thread may be reading it */
return Qnil;
}
if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
rb_raise(rb_eIOError, "closing non-duplex IO for reading");
}
return rb_io_close(io);
}
Closes the stream for reading if open for reading; returns nil
. See Open and Closed Streams.
If the stream was opened by IO.popen
and is also closed for writing, sets global variable $?
(child exit status).
Example:
IO.popen('ruby', 'r+') do |pipe| puts pipe.closed? pipe.close_write puts pipe.closed? pipe.close_read puts $? puts pipe.closed? end
Output:
false false pid 14748 exit 0 true
Related: IO#close
, IO#close_write
, IO#closed?
.
static VALUE
rb_io_close_write(VALUE io)
{
rb_io_t *fptr;
VALUE write_io;
write_io = GetWriteIO(io);
fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
if (fptr->fd < 0) return Qnil;
if (is_socket(fptr->fd, fptr->pathv)) {
#ifndef SHUT_WR
# define SHUT_WR 1
#endif
if (shutdown(fptr->fd, SHUT_WR) < 0)
rb_sys_fail_path(fptr->pathv);
fptr->mode &= ~FMODE_WRITABLE;
if (!(fptr->mode & FMODE_READABLE))
return rb_io_close(write_io);
return Qnil;
}
if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
rb_raise(rb_eIOError, "closing non-duplex IO for writing");
}
if (io != write_io) {
fptr = rb_io_get_fptr(rb_io_taint_check(io));
fptr->tied_io_for_writing = 0;
}
rb_io_close(write_io);
return Qnil;
}
Closes the stream for writing if open for writing; returns nil
. See Open and Closed Streams.
Flushes any buffered writes to the operating system before closing.
If the stream was opened by IO.popen
and is also closed for reading, sets global variable $?
(child exit status).
IO.popen('ruby', 'r+') do |pipe| puts pipe.closed? pipe.close_read puts pipe.closed? pipe.close_write puts $? puts pipe.closed? end
Output:
false false pid 15044 exit 0 true
Related: IO#close
, IO#close_read
, IO#closed?
.
VALUE
rb_io_closed_p(VALUE io)
{
rb_io_t *fptr;
VALUE write_io;
rb_io_t *write_fptr;
write_io = GetWriteIO(io);
if (io != write_io) {
write_fptr = RFILE(write_io)->fptr;
if (write_fptr && 0 <= write_fptr->fd) {
return Qfalse;
}
}
fptr = rb_io_get_fptr(io);
return RBOOL(0 > fptr->fd);
}
Returns true
if the stream is closed for both reading and writing, false
otherwise. See Open and Closed Streams.
IO.popen('ruby', 'r+') do |pipe| puts pipe.closed? pipe.close_read puts pipe.closed? pipe.close_write puts pipe.closed? end
Output:
false false true
Related: IO#close_read
, IO#close_write
, IO#close
.
static VALUE
console_conmode_get(VALUE io)
{
conmode t;
int fd = GetReadFD(io);
if (!getattr(fd, &t)) sys_fail(io);
return conmode_new(cConmode, &t);
}
Returns a data represents the current console mode.
You must require ‘io/console’ to use this method.
static VALUE
console_conmode_set(VALUE io, VALUE mode)
{
conmode *t, r;
int fd = GetReadFD(io);
TypedData_Get_Struct(mode, conmode, &conmode_type, t);
r = *t;
if (!setattr(fd, &r)) sys_fail(io);
return mode;
}
Sets the console mode to mode
.
You must require ‘io/console’ to use this method.
static VALUE
console_cooked(VALUE io)
{
return ttymode(io, rb_yield, io, set_cookedmode, NULL);
}
Yields self
within cooked mode.
STDIN.cooked(&:gets)
will read and return a line with echo back and line editing.
You must require ‘io/console’ to use this method.
static VALUE
console_set_cooked(VALUE io)
{
conmode t;
int fd = GetReadFD(io);
if (!getattr(fd, &t)) sys_fail(io);
set_cookedmode(&t, NULL);
if (!setattr(fd, &t)) sys_fail(io);
return io;
}
Enables cooked mode.
If the terminal mode needs to be back, use io.cooked { … }.
You must require ‘io/console’ to use this method.
static VALUE
console_cursor_pos(VALUE io)
{
#ifdef _WIN32
rb_console_size_t ws;
int fd = GetWriteFD(io);
if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
rb_syserr_fail(LAST_ERROR, 0);
}
return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
#else
static const struct query_args query = {"\033[6n", 0};
VALUE resp = console_vt_response(0, 0, io, &query);
VALUE row, column, term;
unsigned int r, c;
if (!RB_TYPE_P(resp, T_ARRAY) || RARRAY_LEN(resp) != 3) return Qnil;
term = RARRAY_AREF(resp, 2);
if (!RB_TYPE_P(term, T_STRING) || RSTRING_LEN(term) != 1) return Qnil;
if (RSTRING_PTR(term)[0] != 'R') return Qnil;
row = RARRAY_AREF(resp, 0);
column = RARRAY_AREF(resp, 1);
rb_ary_resize(resp, 2);
r = NUM2UINT(row) - 1;
c = NUM2UINT(column) - 1;
RARRAY_ASET(resp, 0, INT2NUM(r));
RARRAY_ASET(resp, 1, INT2NUM(c));
return resp;
#endif
}
Returns the current cursor position as a two-element array of integers (row, column)
io.cursor # => [3, 5]
You must require ‘io/console’ to use this method.
static VALUE
console_cursor_set(VALUE io, VALUE cpos)
{
cpos = rb_convert_type(cpos, T_ARRAY, "Array", "to_ary");
if (RARRAY_LEN(cpos) != 2) rb_raise(rb_eArgError, "expected 2D coordinate");
return console_goto(io, RARRAY_AREF(cpos, 0), RARRAY_AREF(cpos, 1));
}
static VALUE
console_cursor_down(VALUE io, VALUE val)
{
return console_move(io, +NUM2INT(val), 0);
}
static VALUE
console_cursor_left(VALUE io, VALUE val)
{
return console_move(io, 0, -NUM2INT(val));
}
static VALUE
console_cursor_right(VALUE io, VALUE val)
{
return console_move(io, 0, +NUM2INT(val));
}
static VALUE
console_cursor_up(VALUE io, VALUE val)
{
return console_move(io, -NUM2INT(val), 0);
}
static VALUE
rb_io_each_line(int argc, VALUE *argv, VALUE io)
{
VALUE str;
struct getline_arg args;
RETURN_ENUMERATOR(io, argc, argv);
prepare_getline_args(argc, argv, &args, io);
if (args.limit == 0)
rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
rb_yield(str);
}
return io;
}
Calls the block with each remaining line read from the stream; returns self
. Does nothing if already at end-of-stream; See Line IO.
With no arguments given, reads lines as determined by line separator $/
:
f = File.new('t.txt') f.each_line {|line| p line } f.each_line {|line| fail 'Cannot happen' } f.close
Output:
"First line\n" "Second line\n" "\n" "Fourth line\n" "Fifth line\n"
With only string argument sep
given, reads lines as determined by line separator sep
; see Line Separator:
f = File.new('t.txt') f.each_line('li') {|line| p line } f.close
Output:
"First li" "ne\nSecond li" "ne\n\nFourth li" "ne\nFifth li" "ne\n"
The two special values for sep
are honored:
f = File.new('t.txt') # Get all into one string. f.each_line(nil) {|line| p line } f.close
Output:
"First line\nSecond line\n\nFourth line\nFifth line\n" f.rewind # Get paragraphs (up to two line separators). f.each_line('') {|line| p line }
Output:
"First line\nSecond line\n\n" "Fourth line\nFifth line\n"
With only integer argument limit
given, limits the number of bytes in each line; see Line Limit:
f = File.new('t.txt') f.each_line(8) {|line| p line } f.close
Output:
"First li" "ne\n" "Second l" "ine\n" "\n" "Fourth l" "ine\n" "Fifth li" "ne\n"
With arguments sep
and limit
given, combines the two behaviors:
-
Calls with the next line as determined by line separator
sep
. -
But returns no more bytes than are allowed by the limit.
Optional keyword argument chomp
specifies whether line separators are to be omitted:
f = File.new('t.txt') f.each_line(chomp: true) {|line| p line } f.close
Output:
"First line" "Second line" "" "Fourth line" "Fifth line"
Returns an Enumerator
if no block is given.
static VALUE
rb_io_each_byte(VALUE io)
{
rb_io_t *fptr;
RETURN_ENUMERATOR(io, 0, 0);
GetOpenFile(io, fptr);
do {
while (fptr->rbuf.len > 0) {
char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
fptr->rbuf.len--;
rb_yield(INT2FIX(*p & 0xff));
rb_io_check_byte_readable(fptr);
errno = 0;
}
READ_CHECK(fptr);
} while (io_fillbuf(fptr) >= 0);
return io;
}
Calls the given block with each byte (0..255) in the stream; returns self
. See Byte IO.
f = File.new('t.rus') a = [] f.each_byte {|b| a << b } a # => [209, 130, 208, 181, 209, 129, 209, 130] f.close
Returns an Enumerator
if no block is given.
Related: IO#each_char
, IO#each_codepoint
.
static VALUE
rb_io_each_char(VALUE io)
{
rb_io_t *fptr;
rb_encoding *enc;
VALUE c;
RETURN_ENUMERATOR(io, 0, 0);
GetOpenFile(io, fptr);
rb_io_check_char_readable(fptr);
enc = io_input_encoding(fptr);
READ_CHECK(fptr);
while (!NIL_P(c = io_getc(fptr, enc))) {
rb_yield(c);
}
return io;
}
Calls the given block with each character in the stream; returns self
. See Character IO.
f = File.new('t.rus') a = [] f.each_char {|c| a << c.ord } a # => [1090, 1077, 1089, 1090] f.close
Returns an Enumerator
if no block is given.
Related: IO#each_byte
, IO#each_codepoint
.
static VALUE
rb_io_each_codepoint(VALUE io)
{
rb_io_t *fptr;
rb_encoding *enc;
unsigned int c;
int r, n;
RETURN_ENUMERATOR(io, 0, 0);
GetOpenFile(io, fptr);
rb_io_check_char_readable(fptr);
READ_CHECK(fptr);
if (NEED_READCONV(fptr)) {
SET_BINARY_MODE(fptr);
r = 1; /* no invalid char yet */
for (;;) {
make_readconv(fptr, 0);
for (;;) {
if (fptr->cbuf.len) {
if (fptr->encs.enc)
r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
fptr->encs.enc);
else
r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
if (!MBCLEN_NEEDMORE_P(r))
break;
if (fptr->cbuf.len == fptr->cbuf.capa) {
rb_raise(rb_eIOError, "too long character");
}
}
if (more_char(fptr) == MORE_CHAR_FINISHED) {
clear_readconv(fptr);
if (!MBCLEN_CHARFOUND_P(r)) {
enc = fptr->encs.enc;
goto invalid;
}
return io;
}
}
if (MBCLEN_INVALID_P(r)) {
enc = fptr->encs.enc;
goto invalid;
}
n = MBCLEN_CHARFOUND_LEN(r);
if (fptr->encs.enc) {
c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
fptr->encs.enc);
}
else {
c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
}
fptr->cbuf.off += n;
fptr->cbuf.len -= n;
rb_yield(UINT2NUM(c));
rb_io_check_byte_readable(fptr);
}
}
NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
enc = io_input_encoding(fptr);
while (io_fillbuf(fptr) >= 0) {
r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
if (MBCLEN_CHARFOUND_P(r) &&
(n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
fptr->rbuf.off += n;
fptr->rbuf.len -= n;
rb_yield(UINT2NUM(c));
}
else if (MBCLEN_INVALID_P(r)) {
goto invalid;
}
else if (MBCLEN_NEEDMORE_P(r)) {
char cbuf[8], *p = cbuf;
int more = MBCLEN_NEEDMORE_LEN(r);
if (more > numberof(cbuf)) goto invalid;
more += n = fptr->rbuf.len;
if (more > numberof(cbuf)) goto invalid;
while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
(p += n, (more -= n) > 0)) {
if (io_fillbuf(fptr) < 0) goto invalid;
if ((n = fptr->rbuf.len) > more) n = more;
}
r = rb_enc_precise_mbclen(cbuf, p, enc);
if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
c = rb_enc_codepoint(cbuf, p, enc);
rb_yield(UINT2NUM(c));
}
else {
continue;
}
rb_io_check_byte_readable(fptr);
}
return io;
invalid:
rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
UNREACHABLE_RETURN(Qundef);
}
Calls the given block with each codepoint in the stream; returns self
:
f = File.new('t.rus') a = [] f.each_codepoint {|c| a << c } a # => [1090, 1077, 1089, 1090] f.close
Returns an Enumerator
if no block is given.
Related: IO#each_byte
, IO#each_char
.
static VALUE
console_set_echo(VALUE io, VALUE f)
{
conmode t;
int fd = GetReadFD(io);
if (!getattr(fd, &t)) sys_fail(io);
if (RTEST(f))
set_echo(&t, NULL);
else
set_noecho(&t, NULL);
if (!setattr(fd, &t)) sys_fail(io);
return io;
}
Enables/disables echo back. On some platforms, all combinations of this flags and raw/cooked mode may not be valid.
You must require ‘io/console’ to use this method.
static VALUE
console_echo_p(VALUE io)
{
conmode t;
int fd = GetReadFD(io);
if (!getattr(fd, &t)) sys_fail(io);
return echo_p(&t) ? Qtrue : Qfalse;
}
Returns true
if echo back is enabled.
You must require ‘io/console’ to use this method.
VALUE
rb_io_eof(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_check_char_readable(fptr);
if (READ_CHAR_PENDING(fptr)) return Qfalse;
if (READ_DATA_PENDING(fptr)) return Qfalse;
READ_CHECK(fptr);
#if RUBY_CRLF_ENVIRONMENT
if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
return RBOOL(eof(fptr->fd));;
}
#endif
return RBOOL(io_fillbuf(fptr) < 0);
}
Returns true
if the stream is positioned at its end, false
otherwise; see Position:
f = File.open('t.txt') f.eof # => false f.seek(0, :END) # => 0 f.eof # => true f.close
Raises an exception unless the stream is opened for reading; see Mode.
If self
is a stream such as pipe or socket, this method blocks until the other end sends some data or closes it:
r, w = IO.pipe Thread.new { sleep 1; w.close } r.eof? # => true # After 1-second wait. r, w = IO.pipe Thread.new { sleep 1; w.puts "a" } r.eof? # => false # After 1-second wait. r, w = IO.pipe r.eof? # blocks forever
Note that this method reads data to the input byte buffer. So IO#sysread
may not behave as you intend with IO#eof?
, unless you call IO#rewind
first (which is not available for some streams).
static VALUE
console_erase_line(VALUE io, VALUE val)
{
int mode = mode_in_range(val, 2, "line erase");
#ifdef _WIN32
HANDLE h;
rb_console_size_t ws;
COORD *pos = &ws.dwCursorPosition;
DWORD w;
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
if (!GetConsoleScreenBufferInfo(h, &ws)) {
rb_syserr_fail(LAST_ERROR, 0);
}
w = winsize_col(&ws);
switch (mode) {
case 0: /* after cursor */
w -= pos->X;
break;
case 1: /* before *and* cursor */
w = pos->X + 1;
pos->X = 0;
break;
case 2: /* entire line */
pos->X = 0;
break;
}
constat_clear(h, ws.wAttributes, w, *pos);
return io;
#else
rb_io_write(io, rb_sprintf("\x1b[%dK", mode));
#endif
return io;
}
static VALUE
console_erase_screen(VALUE io, VALUE val)
{
int mode = mode_in_range(val, 3, "screen erase");
#ifdef _WIN32
HANDLE h;
rb_console_size_t ws;
COORD *pos = &ws.dwCursorPosition;
DWORD w;
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
if (!GetConsoleScreenBufferInfo(h, &ws)) {
rb_syserr_fail(LAST_ERROR, 0);
}
w = winsize_col(&ws);
switch (mode) {
case 0: /* erase after cursor */
w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
break;
case 1: /* erase before *and* cursor */
w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
pos->X = 0;
pos->Y = ws.srWindow.Top;
break;
case 2: /* erase entire screen */
w = (w * winsize_row(&ws));
pos->X = 0;
pos->Y = ws.srWindow.Top;
break;
case 3: /* erase entire screen */
w = (w * ws.dwSize.Y);
pos->X = 0;
pos->Y = 0;
break;
}
constat_clear(h, ws.wAttributes, w, *pos);
#else
rb_io_write(io, rb_sprintf("\x1b[%dJ", mode));
#endif
return io;
}
IO#expect(pattern,timeout=9999999) → Array
IO#expect(pattern,timeout=9999999) { |result| ... } → nil
# File tmp/rubies/ruby-3.3.0/ext/pty/lib/expect.rb, line 33
def expect(pat,timeout=9999999)
buf = ''.dup
case pat
when String
e_pat = Regexp.new(Regexp.quote(pat))
when Regexp
e_pat = pat
else
raise TypeError, "unsupported pattern class: #{pat.class}"
end
@unusedBuf ||= ''
while true
if not @unusedBuf.empty?
c = @unusedBuf.slice!(0)
elsif !IO.select([self],nil,nil,timeout) or eof? then
result = nil
@unusedBuf = buf
break
else
c = getc
end
buf << c
if $expect_verbose
STDOUT.print c
STDOUT.flush
end
if mat=e_pat.match(buf) then
result = [buf,*mat.captures]
break
end
end
if block_given? then
yield result
else
return result
end
nil
end
The expect
library adds instance method IO#expect
, which is similar to the TCL expect extension.
To use this method, you must require expect
:
require 'expect'
Reads from the IO
until the given pattern
matches or the timeout
is over.
It returns an array with the read buffer, followed by the matches. If a block is given, the result is yielded to the block and returns nil.
When called without a block, it waits until the input that matches the given pattern
is obtained from the IO
or the time specified as the timeout passes. An array is returned when the pattern is obtained from the IO
. The first element of the array is the entire string obtained from the IO
until the pattern matches, followed by elements indicating which the pattern which matched to the anchor in the regular expression.
The optional timeout parameter defines, in seconds, the total time to wait for the pattern. If the timeout expires or eof is found, nil is returned or yielded. However, the buffer in a timeout session is kept for the next expect call. The default timeout is 9999999 seconds.
static VALUE
rb_io_external_encoding(VALUE io)
{
rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
if (fptr->encs.enc2) {
return rb_enc_from_encoding(fptr->encs.enc2);
}
if (fptr->mode & FMODE_WRITABLE) {
if (fptr->encs.enc)
return rb_enc_from_encoding(fptr->encs.enc);
return Qnil;
}
return rb_enc_from_encoding(io_read_encoding(fptr));
}
static VALUE
rb_io_fcntl(int argc, VALUE *argv, VALUE io)
{
VALUE req, arg;
rb_scan_args(argc, argv, "11", &req, &arg);
return rb_fcntl(io, req, arg);
}
Invokes Posix system call fcntl(2), which provides a mechanism for issuing low-level commands to control or query a file-oriented I/O stream. Arguments and results are platform dependent.
If argument
is a number, its value is passed directly; if it is a string, it is interpreted as a binary sequence of bytes. (Array#pack
might be a useful way to build this string.)
Not implemented on all platforms.
static VALUE
rb_io_fdatasync(VALUE io)
{
rb_io_t *fptr;
io = GetWriteIO(io);
GetOpenFile(io, fptr);
if (io_fflush(fptr) < 0)
rb_sys_fail_on_write(fptr);
if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
return INT2FIX(0);
/* fall back */
return rb_io_fsync(io);
}
Immediately writes to disk all data buffered in the stream, via the operating system’s: fdatasync(2)
, if supported, otherwise via fsync(2)
, if supported; otherwise raises an exception.
static VALUE
rb_io_fileno(VALUE io)
{
rb_io_t *fptr = RFILE(io)->fptr;
int fd;
rb_io_check_closed(fptr);
fd = fptr->fd;
return INT2FIX(fd);
}
Returns the integer file descriptor for the stream:
$stdin.fileno # => 0 $stdout.fileno # => 1 $stderr.fileno # => 2 File.open('t.txt').fileno # => 10 f.close
VALUE
rb_io_flush(VALUE io)
{
return rb_io_flush_raw(io, 1);
}
Flushes data buffered in self
to the operating system (but does not necessarily flush data buffered in the operating system):
$stdout.print 'no newline' # Not necessarily flushed. $stdout.flush # Flushed.
static VALUE
rb_io_fsync(VALUE io)
{
rb_io_t *fptr;
io = GetWriteIO(io);
GetOpenFile(io, fptr);
if (io_fflush(fptr) < 0)
rb_sys_fail_on_write(fptr);
if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
rb_sys_fail_path(fptr->pathv);
return INT2FIX(0);
}
Immediately writes to disk all data buffered in the stream, via the operating system’s fsync(2)
.
Note this difference:
-
IO#sync=
: Ensures that data is flushed from the stream’s internal buffers, but does not guarantee that the operating system actually writes the data to disk. -
IO#fsync
: Ensures both that data is flushed from internal buffers, and that data is written to disk.
Raises an exception if the operating system does not support fsync(2)
.
VALUE
rb_io_getbyte(VALUE io)
{
rb_io_t *fptr;
int c;
GetOpenFile(io, fptr);
rb_io_check_byte_readable(fptr);
READ_CHECK(fptr);
VALUE r_stdout = rb_ractor_stdout();
if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
rb_io_t *ofp;
GetOpenFile(r_stdout, ofp);
if (ofp->mode & FMODE_TTY) {
rb_io_flush(r_stdout);
}
}
if (io_fillbuf(fptr) < 0) {
return Qnil;
}
fptr->rbuf.off++;
fptr->rbuf.len--;
c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
return INT2FIX(c & 0xff);
}
Reads and returns the next byte (in range 0..255) from the stream; returns nil
if already at end-of-stream. See Byte IO.
f = File.open('t.txt') f.getbyte # => 70 f.close f = File.open('t.rus') f.getbyte # => 209 f.close
Related: IO#readbyte
(may raise EOFError
).
static VALUE
rb_io_getc(VALUE io)
{
rb_io_t *fptr;
rb_encoding *enc;
GetOpenFile(io, fptr);
rb_io_check_char_readable(fptr);
enc = io_input_encoding(fptr);
READ_CHECK(fptr);
return io_getc(fptr, enc);
}
Reads and returns the next 1-character string from the stream; returns nil
if already at end-of-stream. See Character IO.
f = File.open('t.txt') f.getc # => "F" f.close f = File.open('t.rus') f.getc.ord # => 1090 f.close
Related: IO#readchar
(may raise EOFError
).
static VALUE
console_getch(int argc, VALUE *argv, VALUE io)
{
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
#ifndef _WIN32
return ttymode(io, getc_call, io, set_rawmode, optp);
#else
rb_io_t *fptr;
VALUE str;
wint_t c;
int len;
char buf[8];
wint_t wbuf[2];
# ifndef HAVE_RB_IO_WAIT
struct timeval *to = NULL, tv;
# else
VALUE timeout = Qnil;
# endif
GetOpenFile(io, fptr);
if (optp) {
if (optp->vtime) {
# ifndef HAVE_RB_IO_WAIT
to = &tv;
# else
struct timeval tv;
# endif
tv.tv_sec = optp->vtime / 10;
tv.tv_usec = (optp->vtime % 10) * 100000;
# ifdef HAVE_RB_IO_WAIT
timeout = rb_fiber_scheduler_make_timeout(&tv);
# endif
}
switch (optp->vmin) {
case 1: /* default */
break;
case 0: /* return nil when timed out */
if (optp->vtime) break;
/* fallthru */
default:
rb_warning("min option larger than 1 ignored");
}
if (optp->intr) {
# ifndef HAVE_RB_IO_WAIT
int w = rb_wait_for_single_fd(fptr->fd, RB_WAITFD_IN, to);
if (w < 0) rb_eof_error();
if (!(w & RB_WAITFD_IN)) return Qnil;
# else
VALUE result = rb_io_wait(io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
if (!RTEST(result)) return Qnil;
# endif
}
else if (optp->vtime) {
rb_warning("Non-zero vtime option ignored if intr flag is unset");
}
}
len = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getch, wbuf, RUBY_UBF_IO, 0);
switch (len) {
case 0:
return Qnil;
case 2:
buf[0] = (char)wbuf[0];
c = wbuf[1];
len = 1;
do {
buf[len++] = (unsigned char)c;
} while ((c >>= CHAR_BIT) && len < (int)sizeof(buf));
return rb_str_new(buf, len);
default:
c = wbuf[0];
len = rb_uv_to_utf8(buf, c);
str = rb_utf8_str_new(buf, len);
return rb_str_conv_enc(str, NULL, rb_default_external_encoding());
}
#endif
}
Reads and returns a character in raw mode.
See IO#raw
for details on the parameters.
You must require ‘io/console’ to use this method.
static VALUE
console_getpass(int argc, VALUE *argv, VALUE io)
{
VALUE str, wio;
rb_check_arity(argc, 0, 1);
wio = rb_io_get_write_io(io);
if (wio == io && io == rb_stdin) wio = rb_stderr;
prompt(argc, argv, wio);
rb_io_flush(wio);
str = rb_ensure(getpass_call, io, puts_call, wio);
return str_chomp(str);
}
Reads and returns a line without echo back. Prints prompt
unless it is nil
.
The newline character that terminates the read line is removed from the returned string, see String#chomp!
.
You must require ‘io/console’ to use this method.
require 'io/console' IO::console.getpass("Enter password:") Enter password: # => "mypassword"
static VALUE
rb_io_gets_m(int argc, VALUE *argv, VALUE io)
{
VALUE str;
str = rb_io_getline(argc, argv, io);
rb_lastline_set(str);
return str;
}
Reads and returns a line from the stream; assigns the return value to $_
. See Line IO.
With no arguments given, returns the next line as determined by line separator $/
, or nil
if none:
f = File.open('t.txt') f.gets # => "First line\n" $_ # => "First line\n" f.gets # => "\n" f.gets # => "Fourth line\n" f.gets # => "Fifth line\n" f.gets # => nil f.close
With only string argument sep
given, returns the next line as determined by line separator sep
, or nil
if none; see Line Separator:
f = File.new('t.txt') f.gets('l') # => "First l" f.gets('li') # => "ine\nSecond li" f.gets('lin') # => "ne\n\nFourth lin" f.gets # => "e\n" f.close
The two special values for sep
are honored:
f = File.new('t.txt') # Get all. f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n" f.rewind # Get paragraph (up to two line separators). f.gets('') # => "First line\nSecond line\n\n" f.close
With only integer argument limit
given, limits the number of bytes in the line; see Line Limit:
# No more than one line. File.open('t.txt') {|f| f.gets(10) } # => "First line" File.open('t.txt') {|f| f.gets(11) } # => "First line\n" File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
With arguments sep
and limit
given, combines the two behaviors:
-
Returns the next line as determined by line separator
sep
, ornil
if none. -
But returns no more bytes than are allowed by the limit.
Optional keyword argument chomp
specifies whether line separators are to be omitted:
f = File.open('t.txt') # Chomp the lines. f.gets(chomp: true) # => "First line" f.gets(chomp: true) # => "Second line" f.gets(chomp: true) # => "" f.gets(chomp: true) # => "Fourth line" f.gets(chomp: true) # => "Fifth line" f.gets(chomp: true) # => nil f.close
static VALUE
console_goto(VALUE io, VALUE y, VALUE x)
{
#ifdef _WIN32
COORD pos;
int fd = GetWriteFD(io);
pos.X = NUM2UINT(x);
pos.Y = NUM2UINT(y);
if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
rb_syserr_fail(LAST_ERROR, 0);
}
#else
rb_io_write(io, rb_sprintf("\x1b[%d;%dH", NUM2UINT(y)+1, NUM2UINT(x)+1));
#endif
return io;
}
static VALUE
console_goto_column(VALUE io, VALUE val)
{
#ifdef _WIN32
HANDLE h;
rb_console_size_t ws;
COORD *pos = &ws.dwCursorPosition;
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
if (!GetConsoleScreenBufferInfo(h, &ws)) {
rb_syserr_fail(LAST_ERROR, 0);
}
pos->X = NUM2INT(val);
if (!SetConsoleCursorPosition(h, *pos)) {
rb_syserr_fail(LAST_ERROR, 0);
}
#else
rb_io_write(io, rb_sprintf("\x1b[%dG", NUM2UINT(val)+1));
#endif
return io;
}
static VALUE
console_iflush(VALUE io)
{
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
int fd = GetReadFD(io);
if (tcflush(fd, TCIFLUSH)) sys_fail(io);
#endif
return io;
}
Flushes input buffer in kernel.
You must require ‘io/console’ to use this method.
static VALUE
rb_io_inspect(VALUE obj)
{
rb_io_t *fptr;
VALUE result;
static const char closed[] = " (closed)";
fptr = RFILE(obj)->fptr;
if (!fptr) return rb_any_to_s(obj);
result = rb_str_new_cstr("#<");
rb_str_append(result, rb_class_name(CLASS_OF(obj)));
rb_str_cat2(result, ":");
if (NIL_P(fptr->pathv)) {
if (fptr->fd < 0) {
rb_str_cat(result, closed+1, strlen(closed)-1);
}
else {
rb_str_catf(result, "fd %d", fptr->fd);
}
}
else {
rb_str_append(result, fptr->pathv);
if (fptr->fd < 0) {
rb_str_cat(result, closed, strlen(closed));
}
}
return rb_str_cat2(result, ">");
}
Returns a string representation of self
:
f = File.open('t.txt') f.inspect # => "#<File:t.txt>" f.close
static VALUE
rb_io_internal_encoding(VALUE io)
{
rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
if (!fptr->encs.enc2) return Qnil;
return rb_enc_from_encoding(io_read_encoding(fptr));
}
static VALUE
rb_io_ioctl(int argc, VALUE *argv, VALUE io)
{
VALUE req, arg;
rb_scan_args(argc, argv, "11", &req, &arg);
return rb_ioctl(io, req, arg);
}
Invokes Posix system call ioctl(2), which issues a low-level command to an I/O device.
Issues a low-level command to an I/O device. The arguments and returned value are platform-dependent. The effect of the call is platform-dependent.
If argument argument
is an integer, it is passed directly; if it is a string, it is interpreted as a binary sequence of bytes.
Not implemented on all platforms.
static VALUE
console_ioflush(VALUE io)
{
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
int fd1 = GetReadFD(io);
int fd2 = GetWriteFD(io);
if (fd2 != -1 && fd1 != fd2) {
if (tcflush(fd1, TCIFLUSH)) sys_fail(io);
if (tcflush(fd2, TCOFLUSH)) sys_fail(io);
}
else {
if (tcflush(fd1, TCIOFLUSH)) sys_fail(io);
}
#endif
return io;
}
Flushes input and output buffers in kernel.
You must require ‘io/console’ to use this method.
static VALUE
rb_io_isatty(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
return RBOOL(isatty(fptr->fd) != 0);
}
Returns true
if the stream is associated with a terminal device (tty), false
otherwise:
f = File.new('t.txt').isatty #=> false f.close f = File.new('/dev/tty').isatty #=> true f.close
static VALUE
rb_io_lineno(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_check_char_readable(fptr);
return INT2NUM(fptr->lineno);
}
Returns the current line number for the stream; see Line Number.
static VALUE
rb_io_set_lineno(VALUE io, VALUE lineno)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_check_char_readable(fptr);
fptr->lineno = NUM2INT(lineno);
return lineno;
}
Sets and returns the line number for the stream; see Line Number.
static VALUE
console_noecho(VALUE io)
{
return ttymode(io, rb_yield, io, set_noecho, NULL);
}
Yields self
with disabling echo back.
STDIN.noecho(&:gets)
will read and return a line without echo back.
You must require ‘io/console’ to use this method.
static VALUE
rb_io_nonblock_block(int argc, VALUE *argv, VALUE self)
{
int nb = 1;
int descriptor = rb_io_descriptor(self);
if (argc > 0) {
VALUE v;
rb_scan_args(argc, argv, "01", &v);
nb = RTEST(v);
}
int current_flags = get_fcntl_flags(descriptor);
int restore[2] = {descriptor, current_flags};
if (!io_nonblock_set(descriptor, current_flags, nb))
return rb_yield(self);
return rb_ensure(rb_yield, self, io_nonblock_restore, (VALUE)restore);
}
Yields self
in non-blocking mode.
When false
is given as an argument, self
is yielded in blocking mode. The original mode is restored after the block is executed.
static VALUE
rb_io_nonblock_set(VALUE self, VALUE value)
{
if (RTEST(value)) {
rb_io_t *fptr;
GetOpenFile(self, fptr);
rb_io_set_nonblock(fptr);
}
else {
int descriptor = rb_io_descriptor(self);
io_nonblock_set(descriptor, get_fcntl_flags(descriptor), RTEST(value));
}
return self;
}
Enables non-blocking mode on a stream when set to true
, and blocking mode when set to false
.
This method set or clear O_NONBLOCK flag for the file descriptor in ios.
The behavior of most IO
methods is not affected by this flag because they retry system calls to complete their task after EAGAIN and partial read/write. (An exception is IO#syswrite
which doesn’t retry.)
This method can be used to clear non-blocking mode of standard I/O. Since nonblocking methods (read_nonblock
, etc.) set non-blocking mode but they doesn’t clear it, this method is usable as follows.
END { STDOUT.nonblock = false } STDOUT.write_nonblock("foo")
Since the flag is shared across processes and many non-Ruby commands doesn’t expect standard I/O with non-blocking mode, it would be safe to clear the flag before Ruby program exits.
For example following Ruby program leaves STDIN/STDOUT/STDER non-blocking mode. (STDIN, STDOUT and STDERR are connected to a terminal. So making one of them nonblocking-mode effects other two.) Thus cat command try to read from standard input and it causes “Resource temporarily unavailable” error (EAGAIN).
% ruby -e ' STDOUT.write_nonblock("foo\n")'; cat foo cat: -: Resource temporarily unavailable
Clearing the flag makes the behavior of cat command normal. (cat command waits input from standard input.)
% ruby -rio/nonblock -e ' END { STDOUT.nonblock = false } STDOUT.write_nonblock("foo") '; cat foo
static VALUE
rb_io_nonblock_p(VALUE io)
{
if (get_fcntl_flags(rb_io_descriptor(io)) & O_NONBLOCK)
return Qtrue;
return Qfalse;
}
Returns true
if an IO
object is in non-blocking mode.
static VALUE
io_nread(VALUE io)
{
rb_io_t *fptr;
int len;
ioctl_arg n;
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
len = rb_io_read_pending(fptr);
if (len > 0) return INT2FIX(len);
#ifdef HAVE_RB_IO_DESCRIPTOR
int fd = rb_io_descriptor(io);
#else
int fd = fptr->fd;
#endif
if (!FIONREAD_POSSIBLE_P(fd)) return INT2FIX(0);
if (ioctl(fd, FIONREAD, &n)) return INT2FIX(0);
if (n > 0) return ioctl_arg2num(n);
return INT2FIX(0);
}
Returns number of bytes that can be read without blocking. Returns zero if no information available.
You must require ‘io/wait’ to use this method.
static VALUE
console_oflush(VALUE io)
{
int fd = GetWriteFD(io);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
if (tcflush(fd, TCOFLUSH)) sys_fail(io);
#endif
(void)fd;
return io;
}
Flushes output buffer in kernel.
You must require ‘io/console’ to use this method.
VALUE
rb_io_path(VALUE io)
{
rb_io_t *fptr = RFILE(io)->fptr;
if (!fptr)
return Qnil;
return rb_obj_dup(fptr->pathv);
}
static VALUE
io_pathconf(VALUE io, VALUE arg)
{
int name;
long ret;
name = NUM2INT(arg);
errno = 0;
ret = fpathconf(rb_io_descriptor(io), name);
if (ret == -1) {
if (errno == 0) /* no limit */
return Qnil;
rb_sys_fail("fpathconf");
}
return LONG2NUM(ret);
}
Returns pathname configuration variable using fpathconf().
name should be a constant under Etc
which begins with PC_
.
The return value is an integer or nil. nil means indefinite limit. (fpathconf() returns -1 but errno is not set.)
require 'etc' IO.pipe {|r, w| p w.pathconf(Etc::PC_PIPE_BUF) #=> 4096 }
static VALUE
rb_io_pid(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
if (!fptr->pid)
return Qnil;
return PIDT2NUM(fptr->pid);
}
Returns the process ID of a child process associated with the stream, which will have been set by IO#popen, or nil
if the stream was not created by IO#popen:
pipe = IO.popen("-") if pipe $stderr.puts "In parent, child pid is #{pipe.pid}" else $stderr.puts "In child, pid is #{$$}" end
Output:
In child, pid is 26209 In parent, child pid is 26209
static VALUE
rb_io_set_pos(VALUE io, VALUE offset)
{
rb_io_t *fptr;
rb_off_t pos;
pos = NUM2OFFT(offset);
GetOpenFile(io, fptr);
pos = io_seek(fptr, pos, SEEK_SET);
if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
return OFFT2NUM(pos);
}
static VALUE
rb_io_pread(int argc, VALUE *argv, VALUE io)
{
VALUE len, offset, str;
rb_io_t *fptr;
ssize_t n;
struct prdwr_internal_arg arg = {.io = io};
int shrinkable;
rb_scan_args(argc, argv, "21", &len, &offset, &str);
arg.count = NUM2SIZET(len);
arg.offset = NUM2OFFT(offset);
shrinkable = io_setstrbuf(&str, (long)arg.count);
if (arg.count == 0) return str;
arg.buf = RSTRING_PTR(str);
GetOpenFile(io, fptr);
rb_io_check_byte_readable(fptr);
arg.fd = fptr->fd;
rb_io_check_closed(fptr);
rb_str_locktmp(str);
n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
if (n < 0) {
rb_sys_fail_path(fptr->pathv);
}
io_set_read_length(str, n, shrinkable);
if (n == 0 && arg.count > 0) {
rb_eof_error();
}
return str;
}
Behaves like IO#readpartial
, except that it:
-
Reads at the given
offset
(in bytes). -
Disregards, and does not modify, the stream’s position (see Position).
-
Bypasses any user space buffering in the stream.
Because this method does not disturb the stream’s state (its position, in particular), pread
allows multiple threads and processes to use the same IO object for reading at various offsets.
f = File.open('t.txt') f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n" f.pos # => 52 # Read 12 bytes at offset 0. f.pread(12, 0) # => "First line\n" # Read 9 bytes at offset 8. f.pread(9, 8) # => "ne\nSecon" f.close
Not available on some platforms.
static VALUE
console_key_pressed_p(VALUE io, VALUE k)
{
int vk = -1;
if (FIXNUM_P(k)) {
vk = NUM2UINT(k);
}
else {
const struct vktable *t;
const char *kn;
if (SYMBOL_P(k)) {
k = rb_sym2str(k);
kn = RSTRING_PTR(k);
}
else {
kn = StringValuePtr(k);
}
t = console_win32_vk(kn, RSTRING_LEN(k));
if (!t || (vk = (short)t->vk) == -1) {
rb_raise(rb_eArgError, "unknown virtual key code: % "PRIsVALUE, k);
}
}
return GetKeyState(vk) & 0x80 ? Qtrue : Qfalse;
}
VALUE
rb_io_print(int argc, const VALUE *argv, VALUE out)
{
int i;
VALUE line;
/* if no argument given, print `$_' */
if (argc == 0) {
argc = 1;
line = rb_lastline_get();
argv = &line;
}
if (argc > 1 && !NIL_P(rb_output_fs)) {
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
}
for (i=0; i<argc; i++) {
if (!NIL_P(rb_output_fs) && i>0) {
rb_io_write(out, rb_output_fs);
}
rb_io_write(out, argv[i]);
}
if (argc > 0 && !NIL_P(rb_output_rs)) {
rb_io_write(out, rb_output_rs);
}
return Qnil;
}
Writes the given objects to the stream; returns nil
. Appends the output record separator $OUTPUT_RECORD_SEPARATOR
($\
), if it is not nil
. See Line IO.
With argument objects
given, for each object:
-
Converts via its method
to_s
if not a string. -
Writes to the stream.
-
If not the last object, writes the output field separator
$OUTPUT_FIELD_SEPARATOR
($,
) if it is notnil
.
With default separators:
f = File.open('t.tmp', 'w+') objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero'] p $OUTPUT_RECORD_SEPARATOR p $OUTPUT_FIELD_SEPARATOR f.print(*objects) f.rewind p f.read f.close
Output:
nil nil "00.00/10+0izerozero"
With specified separators:
$\ = "\n" $, = ',' f.rewind f.print(*objects) f.rewind p f.read
Output:
"0,0.0,0/1,0+0i,zero,zero\n"
With no argument given, writes the content of $_
(which is usually the most recent user input):
f = File.open('t.tmp', 'w+') gets # Sets $_ to the most recent user input. f.print f.close
VALUE
rb_io_printf(int argc, const VALUE *argv, VALUE out)
{
rb_io_write(out, rb_f_sprintf(argc, argv));
return Qnil;
}
Formats and writes objects
to the stream.
For details on format_string
, see Format Specifications.
static VALUE
rb_io_putc(VALUE io, VALUE ch)
{
VALUE str;
if (RB_TYPE_P(ch, T_STRING)) {
str = rb_str_substr(ch, 0, 1);
}
else {
char c = NUM2CHR(ch);
str = rb_str_new(&c, 1);
}
rb_io_write(io, str);
return ch;
}
Writes a character to the stream. See Character IO.
If object
is numeric, converts to integer if necessary, then writes the character whose code is the least significant byte; if object
is a string, writes the first character:
$stdout.putc "A" $stdout.putc 65
Output:
AA
VALUE
rb_io_puts(int argc, const VALUE *argv, VALUE out)
{
VALUE line, args[2];
/* if no argument given, print newline. */
if (argc == 0) {
rb_io_write(out, rb_default_rs);
return Qnil;
}
for (int i = 0; i < argc; i++) {
// Convert the argument to a string:
if (RB_TYPE_P(argv[i], T_STRING)) {
line = argv[i];
}
else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
continue;
}
else {
line = rb_obj_as_string(argv[i]);
}
// Write the line:
int n = 0;
if (RSTRING_LEN(line) == 0) {
args[n++] = rb_default_rs;
}
else {
args[n++] = line;
if (!rb_str_end_with_asciichar(line, '\n')) {
args[n++] = rb_default_rs;
}
}
rb_io_writev(out, n, args);
}
return Qnil;
}
Writes the given objects
to the stream, which must be open for writing; returns nil
.\ Writes a newline after each that does not already end with a newline sequence. If called without arguments, writes a newline. See Line IO.
Note that each added newline is the character "\n"<//tt>, not the output record separator (<tt>$\
).
Treatment for each object:
-
String: writes the string.
-
Neither string nor array: writes
object.to_s
. -
Array: writes each element of the array; arrays may be nested.
To keep these examples brief, we define this helper method:
def show(*objects) # Puts objects to file. f = File.new('t.tmp', 'w+') f.puts(objects) # Return file content. f.rewind p f.read f.close end # Strings without newlines. show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n" # Strings, some with newlines. show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n" # Neither strings nor arrays: show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero) # => "0\n0.0\n0/1\n9+0i\nzero\n" # Array of strings. show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n" # Nested arrays. show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
static VALUE
rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
{
rb_io_t *fptr;
ssize_t n;
struct prdwr_internal_arg arg = {.io = io};
VALUE tmp;
if (!RB_TYPE_P(str, T_STRING))
str = rb_obj_as_string(str);
arg.offset = NUM2OFFT(offset);
io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
arg.fd = fptr->fd;
tmp = rb_str_tmp_frozen_acquire(str);
arg.buf = RSTRING_PTR(tmp);
arg.count = (size_t)RSTRING_LEN(tmp);
n = (ssize_t)rb_thread_io_blocking_call(internal_pwrite_func, &arg, fptr->fd, RB_WAITFD_OUT);
if (n < 0) rb_sys_fail_path(fptr->pathv);
rb_str_tmp_frozen_release(str, tmp);
return SSIZET2NUM(n);
}
Behaves like IO#write
, except that it:
-
Writes at the given
offset
(in bytes). -
Disregards, and does not modify, the stream’s position (see Position).
-
Bypasses any user space buffering in the stream.
Because this method does not disturb the stream’s state (its position, in particular), pwrite
allows multiple threads and processes to use the same IO object for writing at various offsets.
f = File.open('t.tmp', 'w+') # Write 6 bytes at offset 3. f.pwrite('ABCDEF', 3) # => 6 f.rewind f.read # => "\u0000\u0000\u0000ABCDEF" f.close
Not available on some platforms.
static VALUE
console_raw(int argc, VALUE *argv, VALUE io)
{
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
return ttymode(io, rb_yield, io, set_rawmode, optp);
}
Yields self
within raw mode, and returns the result of the block.
STDIN.raw(&:gets)
will read and return a line without echo back and line editing.
The parameter min
specifies the minimum number of bytes that should be received when a read operation is performed. (default: 1)
The parameter time
specifies the timeout in seconds with a precision of 1/10 of a second. (default: 0)
If the parameter intr
is true
, enables break, interrupt, quit, and suspend special characters.
Refer to the manual page of termios for further details.
You must require ‘io/console’ to use this method.
static VALUE
console_set_raw(int argc, VALUE *argv, VALUE io)
{
conmode t;
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
int fd = GetReadFD(io);
if (!getattr(fd, &t)) sys_fail(io);
set_rawmode(&t, optp);
if (!setattr(fd, &t)) sys_fail(io);
return io;
}
Enables raw mode, and returns io
.
If the terminal mode needs to be back, use io.raw { ... }
.
See IO#raw
for details on the parameters.
You must require ‘io/console’ to use this method.
static VALUE
io_read(int argc, VALUE *argv, VALUE io)
{
rb_io_t *fptr;
long n, len;
VALUE length, str;
int shrinkable;
#if RUBY_CRLF_ENVIRONMENT
int previous_mode;
#endif
rb_scan_args(argc, argv, "02", &length, &str);
if (NIL_P(length)) {
GetOpenFile(io, fptr);
rb_io_check_char_readable(fptr);
return read_all(fptr, remain_size(fptr), str);
}
len = NUM2LONG(length);
if (len < 0) {
rb_raise(rb_eArgError, "negative length %ld given", len);
}
shrinkable = io_setstrbuf(&str,len);
GetOpenFile(io, fptr);
rb_io_check_byte_readable(fptr);
if (len == 0) {
io_set_read_length(str, 0, shrinkable);
return str;
}
READ_CHECK(fptr);
#if RUBY_CRLF_ENVIRONMENT
previous_mode = set_binary_mode_with_seek_cur(fptr);
#endif
n = io_fread(str, 0, len, fptr);
io_set_read_length(str, n, shrinkable);
#if RUBY_CRLF_ENVIRONMENT
if (previous_mode == O_TEXT) {
setmode(fptr->fd, O_TEXT);
}
#endif
if (n == 0) return Qnil;
return str;
}
Reads bytes from the stream; the stream must be opened for reading (see Access Modes):
-
If
maxlen
isnil
, reads all bytes using the stream’s data mode. -
Otherwise reads up to
maxlen
bytes in binary mode.
Returns a string (either a new string or the given out_string
) containing the bytes read. The encoding of the string depends on both maxLen
and out_string
:
-
maxlen
isnil
: uses internal encoding ofself
(regardless of whetherout_string
was given). -
maxlen
notnil
:-
out_string
given: encoding ofout_string
not modified. -
out_string
not given: ASCII-8BIT is used.
-
Without Argument out_string
When argument out_string
is omitted, the returned value is a new string:
f = File.new('t.txt') f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n" f.rewind f.read(30) # => "First line\r\nSecond line\r\n\r\nFou" f.read(30) # => "rth line\r\nFifth line\r\n" f.read(30) # => nil f.close
If maxlen
is zero, returns an empty string.
With Argument out_string
When argument out_string
is given, the returned value is out_string
, whose content is replaced:
f = File.new('t.txt') s = 'foo' # => "foo" f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n" s # => "First line\nSecond line\n\nFourth line\nFifth line\n" f.rewind s = 'bar' f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou" s # => "First line\r\nSecond line\r\n\r\nFou" s = 'baz' f.read(30, s) # => "rth line\r\nFifth line\r\n" s # => "rth line\r\nFifth line\r\n" s = 'bat' f.read(30, s) # => nil s # => "" f.close
Note that this method behaves like the fread() function in C. This means it retries to invoke read(2) system calls to read data with the specified maxlen (or until EOF).
This behavior is preserved even if the stream is in non-blocking mode. (This method is non-blocking-flag insensitive as other methods.)
If you need the behavior like a single read(2) system call, consider readpartial
, read_nonblock
, and sysread
.
Related: IO#write
.
# File tmp/rubies/ruby-3.3.0/io.rb, line 62
def read_nonblock(len, buf = nil, exception: true)
Primitive.io_read_nonblock(len, buf, exception)
end
Reads at most maxlen bytes from ios using the read(2) system call after O_NONBLOCK is set for the underlying file descriptor.
If the optional outbuf argument is present, it must reference a String
, which will receive the data. The outbuf will contain only the received data after the method call even if it is not empty at the beginning.
read_nonblock
just calls the read(2) system call. It causes all errors the read(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc. The caller should care such errors.
If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN, it is extended by IO::WaitReadable
. So IO::WaitReadable
can be used to rescue the exceptions for retrying read_nonblock.
read_nonblock
causes EOFError
on EOF.
On some platforms, such as Windows, non-blocking mode is not supported on IO
objects other than sockets. In such cases, Errno::EBADF will be raised.
If the read byte buffer is not empty, read_nonblock
reads from the buffer like readpartial. In this case, the read(2) system call is not called.
When read_nonblock
raises an exception kind of IO::WaitReadable
, read_nonblock
should not be called until io is readable for avoiding busy loop. This can be done as follows.
# emulates blocking read (readpartial). begin result = io.read_nonblock(maxlen) rescue IO::WaitReadable IO.select([io]) retry end
Although IO#read_nonblock
doesn’t raise IO::WaitWritable
. OpenSSL::Buffering#read_nonblock
can raise IO::WaitWritable
. If IO
and SSL should be used polymorphically, IO::WaitWritable
should be rescued too. See the document of OpenSSL::Buffering#read_nonblock
for sample code.
Note that this method is identical to readpartial except the non-blocking flag is set.
By specifying a keyword argument exception to false
, you can indicate that read_nonblock
should not raise an IO::WaitReadable
exception, but return the symbol :wait_readable
instead. At EOF, it will return nil instead of raising EOFError
.
static VALUE
rb_io_readbyte(VALUE io)
{
VALUE c = rb_io_getbyte(io);
if (NIL_P(c)) {
rb_eof_error();
}
return c;
}
Reads and returns the next byte (in range 0..255) from the stream; raises EOFError
if already at end-of-stream. See Byte IO.
f = File.open('t.txt') f.readbyte # => 70 f.close f = File.open('t.rus') f.readbyte # => 209 f.close
Related: IO#getbyte
(will not raise EOFError
).
static VALUE
rb_io_readchar(VALUE io)
{
VALUE c = rb_io_getc(io);
if (NIL_P(c)) {
rb_eof_error();
}
return c;
}
Reads and returns the next 1-character string from the stream; raises EOFError
if already at end-of-stream. See Character IO.
f = File.open('t.txt') f.readchar # => "F" f.close f = File.open('t.rus') f.readchar.ord # => 1090 f.close
# File tmp/rubies/ruby-3.3.0/io.rb, line 133
def readline(sep = $/, limit = nil, chomp: false)
Primitive.io_readline(sep, limit, chomp)
end
static VALUE
rb_io_readlines(int argc, VALUE *argv, VALUE io)
{
struct getline_arg args;
prepare_getline_args(argc, argv, &args, io);
return io_readlines(&args, io);
}
Reads and returns all remaining line from the stream; does not modify $_
. See Line IO.
With no arguments given, returns lines as determined by line separator $/
, or nil
if none:
f = File.new('t.txt') f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"] f.readlines # => [] f.close
With only string argument sep
given, returns lines as determined by line separator sep
, or nil
if none; see Line Separator:
f = File.new('t.txt') f.readlines('li') # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"] f.close
The two special values for sep
are honored:
f = File.new('t.txt') # Get all into one string. f.readlines(nil) # => ["First line\nSecond line\n\nFourth line\nFifth line\n"] # Get paragraphs (up to two line separators). f.rewind f.readlines('') # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"] f.close
With only integer argument limit
given, limits the number of bytes in each line; see Line Limit:
f = File.new('t.txt') f.readlines(8) # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"] f.close
With arguments sep
and limit
given, combines the two behaviors:
-
Returns lines as determined by line separator
sep
. -
But returns no more bytes in a line than are allowed by the limit.
Optional keyword argument chomp
specifies whether line separators are to be omitted:
f = File.new('t.txt') f.readlines(chomp: true) # => ["First line", "Second line", "", "Fourth line", "Fifth line"] f.close
static VALUE
io_readpartial(int argc, VALUE *argv, VALUE io)
{
VALUE ret;
ret = io_getpartial(argc, argv, io, Qnil, 0);
if (NIL_P(ret))
rb_eof_error();
return ret;
}
Reads up to maxlen
bytes from the stream; returns a string (either a new string or the given out_string
). Its encoding is:
-
The unchanged encoding of
out_string
, ifout_string
is given. -
ASCII-8BIT, otherwise.
-
Contains
maxlen
bytes from the stream, if available. -
Otherwise contains all available bytes, if any available.
-
Otherwise is an empty string.
With the single non-negative integer argument maxlen
given, returns a new string:
f = File.new('t.txt') f.readpartial(20) # => "First line\nSecond l" f.readpartial(20) # => "ine\n\nFourth line\n" f.readpartial(20) # => "Fifth line\n" f.readpartial(20) # Raises EOFError. f.close
With both argument maxlen
and string argument out_string
given, returns modified out_string
:
f = File.new('t.txt') s = 'foo' f.readpartial(20, s) # => "First line\nSecond l" s = 'bar' f.readpartial(0, s) # => "" f.close
This method is useful for a stream such as a pipe, a socket, or a tty. It blocks only when no data is immediately available. This means that it blocks only when all of the following are true:
-
The byte buffer in the stream is empty.
-
The content of the stream is empty.
-
The stream is not at EOF.
When blocked, the method waits for either more data or EOF on the stream:
-
If more data is read, the method returns the data.
-
If EOF is reached, the method raises
EOFError
.
When not blocked, the method responds immediately:
-
Returns data from the buffer if there is any.
-
Otherwise returns data from the stream if there is any.
-
Otherwise raises
EOFError
if the stream has reached EOF.
Note that this method is similar to sysread. The differences are:
-
If the byte buffer is not empty, read from the byte buffer instead of “sysread for buffered
IO
(IOError
)”. -
It doesn’t cause Errno::EWOULDBLOCK and Errno::EINTR. When readpartial meets EWOULDBLOCK and EINTR by read system call, readpartial retries the system call.
The latter means that readpartial is non-blocking-flag insensitive. It blocks on the situation IO#sysread
causes Errno::EWOULDBLOCK as if the fd is blocking mode.
Examples:
# # Returned Buffer Content Pipe Content r, w = IO.pipe # w << 'abc' # "" "abc". r.readpartial(4096) # => "abc" "" "" r.readpartial(4096) # (Blocks because buffer and pipe are empty.) # # Returned Buffer Content Pipe Content r, w = IO.pipe # w << 'abc' # "" "abc" w.close # "" "abc" EOF r.readpartial(4096) # => "abc" "" EOF r.readpartial(4096) # raises EOFError # # Returned Buffer Content Pipe Content r, w = IO.pipe # w << "abc\ndef\n" # "" "abc\ndef\n" r.gets # => "abc\n" "def\n" "" w << "ghi\n" # "def\n" "ghi\n" r.readpartial(4096) # => "def\n" "" "ghi\n" r.readpartial(4096) # => "ghi\n" "" ""
static VALUE
io_ready_p(VALUE io)
{
rb_io_t *fptr;
#ifndef HAVE_RB_IO_WAIT
struct timeval tv = {0, 0};
#endif
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
if (rb_io_read_pending(fptr)) return Qtrue;
#ifndef HAVE_RB_IO_WAIT
return wait_for_single_fd(fptr, RB_WAITFD_IN, &tv) ? Qtrue : Qfalse;
#else
return io_wait_event(io, RUBY_IO_READABLE, RB_INT2NUM(0), 1);
#endif
}
Returns a truthy value if input available without blocking, or a falsy value.
You must require ‘io/wait’ to use this method.
static VALUE
rb_io_reopen(int argc, VALUE *argv, VALUE file)
{
VALUE fname, nmode, opt;
int oflags;
rb_io_t *fptr;
if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
VALUE tmp = rb_io_check_io(fname);
if (!NIL_P(tmp)) {
return io_reopen(file, tmp);
}
}
FilePathValue(fname);
rb_io_taint_check(file);
fptr = RFILE(file)->fptr;
if (!fptr) {
fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
}
if (!NIL_P(nmode) || !NIL_P(opt)) {
int fmode;
struct rb_io_encoding convconfig;
rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
if (RUBY_IO_EXTERNAL_P(fptr) &&
((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
(fptr->mode & FMODE_READWRITE)) {
rb_raise(rb_eArgError,
"%s can't change access mode from \"%s\" to \"%s\"",
PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
rb_io_fmode_modestr(fmode));
}
fptr->mode = fmode;
fptr->encs = convconfig;
}
else {
oflags = rb_io_fmode_oflags(fptr->mode);
}
fptr->pathv = fname;
if (fptr->fd < 0) {
fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
fptr->stdio_file = 0;
return file;
}
if (fptr->mode & FMODE_WRITABLE) {
if (io_fflush(fptr) < 0)
rb_sys_fail_on_write(fptr);
}
fptr->rbuf.off = fptr->rbuf.len = 0;
if (fptr->stdio_file) {
int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
rb_io_oflags_modestr(oflags),
fptr->stdio_file);
if (e) rb_syserr_fail_path(e, fptr->pathv);
fptr->fd = fileno(fptr->stdio_file);
rb_fd_fix_cloexec(fptr->fd);
#ifdef USE_SETVBUF
if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
#endif
if (fptr->stdio_file == stderr) {
if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
}
else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
}
}
else {
int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
int err = 0;
if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
err = errno;
(void)close(tmpfd);
if (err) {
rb_syserr_fail_path(err, fptr->pathv);
}
}
return file;
}
Reassociates the stream with another stream, which may be of a different class. This method may be used to redirect an existing stream to a new destination.
With argument other_io
given, reassociates with that stream:
# Redirect $stdin from a file. f = File.open('t.txt') $stdin.reopen(f) f.close # Redirect $stdout to a file. f = File.open('t.tmp', 'w') $stdout.reopen(f) f.close
With argument path
given, reassociates with a new stream to that file path:
$stdin.reopen('t.txt') $stdout.reopen('t.tmp', 'w')
Optional keyword arguments opts
specify:
-
Encoding options.
static VALUE
rb_io_rewind(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
if (io == ARGF.current_file) {
ARGF.lineno -= fptr->lineno;
}
fptr->lineno = 0;
if (fptr->readconv) {
clear_readconv(fptr);
}
return INT2FIX(0);
}
Repositions the stream to its beginning, setting both the position and the line number to zero; see Position and Line Number:
f = File.open('t.txt') f.tell # => 0 f.lineno # => 0 f.gets # => "First line\n" f.tell # => 12 f.lineno # => 1 f.rewind # => 0 f.tell # => 0 f.lineno # => 0 f.close
Note that this method cannot be used with streams such as pipes, ttys, and sockets.
static VALUE
console_scroll_backward(VALUE io, VALUE val)
{
return console_scroll(io, -NUM2INT(val));
}
static VALUE
console_scroll_forward(VALUE io, VALUE val)
{
return console_scroll(io, +NUM2INT(val));
}
static VALUE
rb_io_seek_m(int argc, VALUE *argv, VALUE io)
{
VALUE offset, ptrname;
int whence = SEEK_SET;
if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
whence = interpret_seek_whence(ptrname);
}
return rb_io_seek(io, offset, whence);
}
Seeks to the position given by integer offset
(see Position) and constant whence
, which is one of:
-
:CUR
orIO::SEEK_CUR
: Repositions the stream to its current position plus the givenoffset
:f = File.open('t.txt') f.tell # => 0 f.seek(20, :CUR) # => 0 f.tell # => 20 f.seek(-10, :CUR) # => 0 f.tell # => 10 f.close
-
:END
orIO::SEEK_END
: Repositions the stream to its end plus the givenoffset
:f = File.open('t.txt') f.tell # => 0 f.seek(0, :END) # => 0 # Repositions to stream end. f.tell # => 52 f.seek(-20, :END) # => 0 f.tell # => 32 f.seek(-40, :END) # => 0 f.tell # => 12 f.close
-
:SET
orIO:SEEK_SET
: Repositions the stream to the givenoffset
:f = File.open('t.txt') f.tell # => 0 f.seek(20, :SET) # => 0 f.tell # => 20 f.seek(40, :SET) # => 0 f.tell # => 40 f.close
static VALUE
rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
{
rb_io_t *fptr;
VALUE v1, v2, opt;
if (!RB_TYPE_P(io, T_FILE)) {
return forward(io, id_set_encoding, argc, argv);
}
argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
GetOpenFile(io, fptr);
io_encoding_set(fptr, v1, v2, opt);
return io;
}
See Encodings.
Argument ext_enc
, if given, must be an Encoding
object or a String
with the encoding name; it is assigned as the encoding for the stream.
Argument int_enc
, if given, must be an Encoding
object or a String
with the encoding name; it is assigned as the encoding for the internal string.
Argument 'ext_enc:int_enc'
, if given, is a string containing two colon-separated encoding names; corresponding Encoding
objects are assigned as the external and internal encodings for the stream.
If the external encoding of a string is binary/ASCII-8BIT, the internal encoding of the string is set to nil, since no transcoding is needed.
Optional keyword arguments enc_opts
specify Encoding options.
static VALUE
rb_io_set_encoding_by_bom(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
if (!(fptr->mode & FMODE_BINMODE)) {
rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
}
if (fptr->encs.enc2) {
rb_raise(rb_eArgError, "encoding conversion is set");
}
else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
rb_raise(rb_eArgError, "encoding is set to %s already",
rb_enc_name(fptr->encs.enc));
}
if (!io_set_encoding_by_bom(io)) return Qnil;
return rb_enc_from_encoding(fptr->encs.enc);
}
If the stream begins with a BOM (byte order marker), consumes the BOM and sets the external encoding accordingly; returns the result encoding if found, or nil
otherwise:
File.write('t.tmp', "\u{FEFF}abc") io = File.open('t.tmp', 'rb') io.set_encoding_by_bom # => #<Encoding:UTF-8> io.close File.write('t.tmp', 'abc') io = File.open('t.tmp', 'rb') io.set_encoding_by_bom # => nil io.close
Raises an exception if the stream is not binmode or its encoding has already been set.
static VALUE
rb_io_stat(VALUE obj)
{
rb_io_t *fptr;
struct stat st;
GetOpenFile(obj, fptr);
if (fstat(fptr->fd, &st) == -1) {
rb_sys_fail_path(fptr->pathv);
}
return rb_stat_new(&st);
}
Returns status information for ios as an object of type File::Stat
.
f = File.new("testfile") s = f.stat "%o" % s.mode #=> "100644" s.blksize #=> 4096 s.atime #=> Wed Apr 09 08:53:54 CDT 2003
static VALUE
rb_io_sync(VALUE io)
{
rb_io_t *fptr;
io = GetWriteIO(io);
GetOpenFile(io, fptr);
return RBOOL(fptr->mode & FMODE_SYNC);
}
Returns the current sync mode of the stream. When sync mode is true, all output is immediately flushed to the underlying operating system and is not buffered by Ruby internally. See also fsync
.
f = File.open('t.tmp', 'w') f.sync # => false f.sync = true f.sync # => true f.close
static VALUE
rb_io_set_sync(VALUE io, VALUE sync)
{
rb_io_t *fptr;
io = GetWriteIO(io);
GetOpenFile(io, fptr);
if (RTEST(sync)) {
fptr->mode |= FMODE_SYNC;
}
else {
fptr->mode &= ~FMODE_SYNC;
}
return sync;
}
Sets the sync mode for the stream to the given value; returns the given value.
Values for the sync mode:
-
true
: All output is immediately flushed to the underlying operating system and is not buffered internally. -
false
: Output may be buffered internally.
Example;
f = File.open('t.tmp', 'w') f.sync # => false f.sync = true f.sync # => true f.close
Related: IO#fsync
.
static VALUE
rb_io_sysread(int argc, VALUE *argv, VALUE io)
{
VALUE len, str;
rb_io_t *fptr;
long n, ilen;
struct io_internal_read_struct iis;
int shrinkable;
rb_scan_args(argc, argv, "11", &len, &str);
ilen = NUM2LONG(len);
shrinkable = io_setstrbuf(&str, ilen);
if (ilen == 0) return str;
GetOpenFile(io, fptr);
rb_io_check_byte_readable(fptr);
if (READ_DATA_BUFFERED(fptr)) {
rb_raise(rb_eIOError, "sysread for buffered IO");
}
rb_io_check_closed(fptr);
io_setstrbuf(&str, ilen);
iis.th = rb_thread_current();
iis.fptr = fptr;
iis.nonblock = 0;
iis.fd = fptr->fd;
iis.buf = RSTRING_PTR(str);
iis.capa = ilen;
iis.timeout = NULL;
n = io_read_memory_locktmp(str, &iis);
if (n < 0) {
rb_sys_fail_path(fptr->pathv);
}
io_set_read_length(str, n, shrinkable);
if (n == 0 && ilen > 0) {
rb_eof_error();
}
return str;
}
Behaves like IO#readpartial
, except that it uses low-level system functions.
This method should not be used with other stream-reader methods.
static VALUE
rb_io_sysseek(int argc, VALUE *argv, VALUE io)
{
VALUE offset, ptrname;
int whence = SEEK_SET;
rb_io_t *fptr;
rb_off_t pos;
if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
whence = interpret_seek_whence(ptrname);
}
pos = NUM2OFFT(offset);
GetOpenFile(io, fptr);
if ((fptr->mode & FMODE_READABLE) &&
(READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
rb_raise(rb_eIOError, "sysseek for buffered IO");
}
if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
rb_warn("sysseek for buffered IO");
}
errno = 0;
pos = lseek(fptr->fd, pos, whence);
if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
return OFFT2NUM(pos);
}
Behaves like IO#seek
, except that it:
-
Uses low-level system functions.
-
Returns the new position.
static VALUE
rb_io_syswrite(VALUE io, VALUE str)
{
VALUE tmp;
rb_io_t *fptr;
long n, len;
const char *ptr;
if (!RB_TYPE_P(str, T_STRING))
str = rb_obj_as_string(str);
io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
if (fptr->wbuf.len) {
rb_warn("syswrite for buffered IO");
}
tmp = rb_str_tmp_frozen_acquire(str);
RSTRING_GETMEM(tmp, ptr, len);
n = rb_io_write_memory(fptr, ptr, len);
if (n < 0) rb_sys_fail_path(fptr->pathv);
rb_str_tmp_frozen_release(str, tmp);
return LONG2FIX(n);
}
Writes the given object
to self, which must be opened for writing (see Modes); returns the number bytes written. If object
is not a string is converted via method to_s:
f = File.new('t.tmp', 'w') f.syswrite('foo') # => 3 f.syswrite(30) # => 2 f.syswrite(:foo) # => 3 f.close
This methods should not be used with other stream-writer methods.
static VALUE
rb_io_tell(VALUE io)
{
rb_io_t *fptr;
rb_off_t pos;
GetOpenFile(io, fptr);
pos = io_tell(fptr);
if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
pos -= fptr->rbuf.len;
return OFFT2NUM(pos);
}
VALUE
rb_io_timeout(VALUE self)
{
rb_io_t *fptr = rb_io_get_fptr(self);
return fptr->timeout;
}
Get the internal timeout duration or nil if it was not set.
VALUE
rb_io_set_timeout(VALUE self, VALUE timeout)
{
// Validate it:
if (RTEST(timeout)) {
rb_time_interval(timeout);
}
rb_io_t *fptr = rb_io_get_fptr(self);
fptr->timeout = timeout;
return self;
}
Sets the internal timeout to the specified duration or nil. The timeout applies to all blocking operations where possible.
When the operation performs longer than the timeout set, IO::TimeoutError
is raised.
This affects the following methods (but is not limited to): gets
, puts
, read
, write
, wait_readable
and wait_writable
. This also affects blocking socket operations like Socket#accept
and Socket#connect
.
Some operations like File#open
and IO#close
are not affected by the timeout. A timeout during a write operation may leave the IO
in an inconsistent state, e.g. data was partially written. Generally speaking, a timeout is a last ditch effort to prevent an application from hanging on slow I/O operations, such as those that occur during a slowloris attack.
VALUE
rb_io_ungetbyte(VALUE io, VALUE b)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_check_byte_readable(fptr);
switch (TYPE(b)) {
case T_NIL:
return Qnil;
case T_FIXNUM:
case T_BIGNUM: ;
VALUE v = rb_int_modulo(b, INT2FIX(256));
unsigned char c = NUM2INT(v) & 0xFF;
b = rb_str_new((const char *)&c, 1);
break;
default:
SafeStringValue(b);
}
io_ungetbyte(b, fptr);
return Qnil;
}
Pushes back (“unshifts”) the given data onto the stream’s buffer, placing the data so that it is next to be read; returns nil
. See Byte IO.
Note that:
-
Calling the method has no effect with unbuffered reads (such as
IO#sysread
). -
Calling
rewind
on the stream discards the pushed-back data.
When argument integer
is given, uses only its low-order byte:
File.write('t.tmp', '012') f = File.open('t.tmp') f.ungetbyte(0x41) # => nil f.read # => "A012" f.rewind f.ungetbyte(0x4243) # => nil f.read # => "C012" f.close
When argument string
is given, uses all bytes:
File.write('t.tmp', '012') f = File.open('t.tmp') f.ungetbyte('A') # => nil f.read # => "A012" f.rewind f.ungetbyte('BCDE') # => nil f.read # => "BCDE012" f.close
VALUE
rb_io_ungetc(VALUE io, VALUE c)
{
rb_io_t *fptr;
long len;
GetOpenFile(io, fptr);
rb_io_check_char_readable(fptr);
if (FIXNUM_P(c)) {
c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
}
else if (RB_BIGNUM_TYPE_P(c)) {
c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
}
else {
SafeStringValue(c);
}
if (NEED_READCONV(fptr)) {
SET_BINARY_MODE(fptr);
len = RSTRING_LEN(c);
#if SIZEOF_LONG > SIZEOF_INT
if (len > INT_MAX)
rb_raise(rb_eIOError, "ungetc failed");
#endif
make_readconv(fptr, (int)len);
if (fptr->cbuf.capa - fptr->cbuf.len < len)
rb_raise(rb_eIOError, "ungetc failed");
if (fptr->cbuf.off < len) {
MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
fptr->cbuf.ptr+fptr->cbuf.off,
char, fptr->cbuf.len);
fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
}
fptr->cbuf.off -= (int)len;
fptr->cbuf.len += (int)len;
MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
}
else {
NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
io_ungetbyte(c, fptr);
}
return Qnil;
}
Pushes back (“unshifts”) the given data onto the stream’s buffer, placing the data so that it is next to be read; returns nil
. See Character IO.
Note that:
-
Calling the method has no effect with unbuffered reads (such as
IO#sysread
). -
Calling
rewind
on the stream discards the pushed-back data.
When argument integer
is given, interprets the integer as a character:
File.write('t.tmp', '012') f = File.open('t.tmp') f.ungetc(0x41) # => nil f.read # => "A012" f.rewind f.ungetc(0x0442) # => nil f.getc.ord # => 1090 f.close
When argument string
is given, uses all characters:
File.write('t.tmp', '012') f = File.open('t.tmp') f.ungetc('A') # => nil f.read # => "A012" f.rewind f.ungetc("\u0442\u0435\u0441\u0442") # => nil f.getc.ord # => 1090 f.getc.ord # => 1077 f.getc.ord # => 1089 f.getc.ord # => 1090 f.close
static VALUE
io_wait(int argc, VALUE *argv, VALUE io)
{
#ifndef HAVE_RB_IO_WAIT
rb_io_t *fptr;
struct timeval timerec;
struct timeval *tv = NULL;
int event = 0;
int i;
GetOpenFile(io, fptr);
for (i = 0; i < argc; ++i) {
if (SYMBOL_P(argv[i])) {
event |= wait_mode_sym(argv[i]);
}
else {
*(tv = &timerec) = rb_time_interval(argv[i]);
}
}
/* rb_time_interval() and might_mode() might convert the argument */
rb_io_check_closed(fptr);