Spec-Zone.ru › Ruby 2.7

класс IO

Родитель:
Объект
Включенные модули:
File::File::Constants, Enumerable

Библиотека expect добавляет метод экземпляра IO expect, который выполняет действия, аналогичные расширению expect в tcl.

Для использования этого метода необходимо подключить expect:

require 'expect'

Обратитесь к expect для получения информации об использовании.

Класс IO является основой для всех операций ввода-вывода в Ruby. Поток ввода-вывода может быть дуплексным (то есть двунаправленным) и, следовательно, может использовать более одного системного потока.

Многие примеры в этом разделе используют класс File, единственный стандартный подкласс IO. Эти два класса тесно связаны. Как и класс File, библиотека Socket наследуется от IO (например, TCPSocket или UDPSocket).

Метод Kernel#open может создать объект IO (или File) для следующих типов аргументов:

  • Простая строка представляет имя файла, подходящее для операционной системы.

  • Строка, начинающаяся с "|" , указывает на подпроцесс. Остальная часть строки после "|" вызывается как процесс с соответствующими каналами ввода/вывода, подключенными к нему.

  • Строка, равная "|-" , создаст другой экземпляр Ruby как подпроцесс.

Объект IO может быть открыт с различными режимами файлов (только чтение, только запись) и кодировками для правильного преобразования. См. IO.new для этих вариантов. См. Kernel#open для получения подробной информации о различных форматах команд, описанных выше.

IO.popen, библиотека Open3 или Process#spawn также могут использоваться для взаимодействия с подпроцессами через IO.

Ruby будет преобразовывать пути между различными соглашениями об именах операционных систем, если это возможно. Например, в системе Windows имя файла "/gumby/ruby/test.rb" будет открыто как "\gumby\ruby\test.rb". При указании имени файла в стиле Windows в строке Ruby помните об экранировании обратных слэшей:

"C:\\gumby\\ruby\\test.rb"

В наших примерах здесь будут использоваться слэши Unix; File::ALT_SEPARATOR можно использовать для получения символа разделителя, специфичного для платформы.

Глобальная константа ARGF (также доступная как $<) предоставляет поток, подобный IO, который позволяет получить доступ ко всем файлам, упомянутым в командной строке (или STDIN, если файлы не указаны). ARGF#path и его псевдоним ARGF#filename предоставляются для доступа к имени файла, который в данный момент читается.

io/console

Расширение io/console предоставляет методы для взаимодействия с консолью. К консоли можно получить доступ из IO.console или стандартных объектов ввода/вывода/ошибок IO.

Подключение io/console добавляет следующие методы:

  • IO::console

  • IO#raw

  • IO#raw!

  • IO#cooked

  • IO#cooked!

  • IO#getch

  • IO#echo=

  • IO#echo?

  • IO#noecho

  • IO#winsize

  • IO#winsize=

  • IO#iflush

  • IO#ioflush

  • IO#oflush

Пример:

require 'io/console'
rows, columns = $stdout.winsize
puts "Your screen is #{columns} wide and #{rows} tall"

Константы

EWOULDBLOCKWaitReadable

EAGAINWaitReadable

EWOULDBLOCKWaitWritable

EAGAINWaitWritable

SEEK_CUR

Set Позиция ввода-вывода от текущей позиции

SEEK_DATA

Set Позиция ввода-вывода до следующего местоположения, содержащего данные

SEEK_END

Set Позиция ввода-вывода от конца

SEEK_HOLE

Set Позиция ввода-вывода до следующей дыры

SEEK_SET

Set Позиция ввода-вывода с начала

Методы публичного класса

binread(name, [length [, offset]] ) → строка Показать исходный код
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
    };
    convconfig_t 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);
}

Открывает файл, по желанию переходит к указанному смещению, затем возвращает длина байт (по умолчанию — до конца файла). binread гарантирует, что файл будет закрыт перед возвратом. Режим открытия будет "rb:ASCII-8BIT".

IO.binread("testfile")           #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
IO.binread("testfile", 20)       #=> "This is line one\nThi"
IO.binread("testfile", 20, 10)   #=> "ne one\nThis is line "
binwrite(name, строка, [offset] ) → целое Показать исходный код
binwrite(name, строка, [offset], open_args ) → целое
static VALUE
rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
{
    return io_s_write(argc, argv, io, 1);
}

То же, что и IO.write, за исключением открытия файла в двоичном режиме и кодировке ASCII-8BIT ("wb:ASCII-8BIT").

console → #<Файл:/dev/tty> Показать исходный код
console(sym, *args)
static VALUE
console_dev(int argc, VALUE *argv, VALUE klass)
{
    VALUE con = 0;
    rb_io_t *fptr;
    VALUE sym = 0;

    rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
    if (argc) {
        Check_Type(sym = argv[0], T_SYMBOL);
    }
    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) ||
            (!(fptr = RFILE(con)->fptr) || GetReadFD(fptr) == -1)) {
            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) {
        VALUE args[2];
#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;

#ifdef CONSOLE_DEVICE_FOR_WRITING
        fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
        if (fd < 0) return Qnil;
        rb_update_max_fd(fd);
        args[1] = INT2FIX(O_WRONLY);
        args[0] = INT2NUM(fd);
        out = rb_class_new_instance(2, args, klass);
#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;
        }
        rb_update_max_fd(fd);
        args[1] = INT2FIX(O_RDWR);
        args[0] = INT2NUM(fd);
        con = rb_class_new_instance(2, args, klass);
        GetOpenFile(con, fptr);
        fptr->pathv = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
#ifdef CONSOLE_DEVICE_FOR_WRITING
        GetOpenFile(out, ofptr);
        ofptr->pathv = fptr->pathv;
        fptr->tied_io_for_writing = out;
        ofptr->mode |= FMODE_SYNC;
#endif
        fptr->mode |= FMODE_SYNC;
        rb_const_set(klass, id_console, con);
    }
    if (sym) {
        return rb_f_send(argc, argv, con);
    }
    return con;
}

Возвращает экземпляр File, открытый в консоли.

Если sym задан, он будет отправлен в открытую консоль с args и результат будет возвращен вместо консольного IO объекта.

Для использования этого метода необходимо подключить 'io/console'.

copy_stream(src, dst) Показать исходный код
copy_stream(src, dst, copy_length)
copy_stream(src, dst, copy_length, src_offset)
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;

    if (NIL_P(length))
        st.copy_length = (off_t)-1;
    else
        st.copy_length = NUM2OFFT(length);

    if (NIL_P(src_offset))
        st.src_offset = (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);
}

IO.copy_stream копирует src в dst. src и dst — это либо имя файла, либо объект, подобный IO. Объект, подобный IO, для src должен иметь метод readpartial или read. Объект, подобный IO, для dst должен иметь метод write. (В соответствующих ситуациях могут использоваться специализированные механизмы, такие как системный вызов sendfile.)

Этот метод возвращает количество скопированных байт.

Если необязательные аргументы не заданы, начальная позиция копирования — начало имени файла или текущее смещение файла объекта IO. Конечная позиция копирования — конец файла.

Если задан copy_length, копируется не более copy_length байт.

Если задан src_offset, он задаёт начальную позицию копирования.

Когда указан src_offset и src — это объект IO, IO.copy_stream не перемещает текущее смещение файла.

for_fd(fd, mode [, opt]) → io Показать исходный код
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;
}

Синоним для IO.new.

foreach(name, sep=$/ [, getline_args, open_args]) {|line| block } → nil Показать исходный код
foreach(name, limit [, getline_args, open_args]) {|line| block } → nil
foreach(name, sep, limit [, getline_args, open_args]) {|line| block } → nil
foreach(...) → перечисление
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, "13:", NULL, 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);
}

Выполняет блок для каждой строки в указанном вводе/выводе, где строки разделены sep.

Если блок не задан, вместо него возвращается перечисление.

IO.foreach("testfile") {|x| print "GOT ", x }

вывод:

GOT This is line one
GOT This is line two
GOT This is line three
GOT And so on...

Если последний аргумент — хеш, это ключевой аргумент для открытия. Подробности о getline_args см. в IO.readlines. Подробности об open_args см. также в IO.read.

new(fd [, mode] [, opt]) → io Показать исходный код
static VALUE
rb_io_initialize(int argc, VALUE *argv, VALUE io)
{
    VALUE fnum, vmode;
    rb_io_t *fp;
    int fd, fmode, oflags = O_RDONLY;
    convconfig_t 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
    if (!NIL_P(opt) && rb_hash_aref(opt, sym_autoclose) == Qfalse) {
        fmode |= FMODE_PREP;
    }
    MakeOpenFile(io, fp);
    fp->fd = fd;
    fp->mode = fmode;
    fp->encs = convconfig;
    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;
}

Возвращает новый объект IO (поток) для заданного целочисленного дескриптора файла fd и mode строки. opt может использоваться для более понятной спецификации частей mode. См. также IO.sysopen и IO.for_fd.

IO.new вызывается различными методами открытия файлов File и IO, такими как IO::open, Kernel#open и File::open.

Режим открытия

Когда mode — целое число, оно должно быть комбинацией режимов, определённых в File::Constants (File::RDONLY, File::WRONLY|File::CREAT). Смотрите страницу руководства open(2) для получения дополнительной информации.

Когда mode — строка, она должна иметь один из следующих форматов:

fmode
fmode ":" ext_enc
fmode ":" ext_enc ":" int_enc
fmode ":" "BOM|UTF-*"

fmode — строка режима открытия IO, ext_enc — внешняя кодировка для IO, а int_enc — внутренняя кодировка.

IO Режим открытия

Ruby поддерживает следующие режимы открытия:

"r"  Read-only, starts at beginning of file  (default mode).

"r+" Read-write, starts at beginning of file.

"w"  Write-only, truncates existing file
     to zero length or creates a new file for writing.

"w+" Read-write, truncates existing file to zero length
     or creates a new file for reading and writing.

"a"  Write-only, each write call appends data at end of file.
     Creates a new file for writing if file does not exist.

"a+" Read-write, each write call appends data at end of file.
     Creates a new file for reading and writing if file does
     not exist.

Следующие режимы должны использоваться отдельно и вместе с одним или несколькими из указанных выше режимов.

"b"  Binary file mode
     Suppresses EOL <-> CRLF conversion on Windows. And
     sets external encoding to ASCII-8BIT unless explicitly
     specified.

"t"  Text file mode

Режим эксклюзивного доступа («x») может использоваться вместе с «w», чтобы гарантировать создание файла. При его уже существующем наличии возбуждается Errno::EEXIST. Он может не поддерживаться со всеми типами потоков (например, с каналами).

Если режим открытия исходного IO является только для чтения, режим нельзя изменить на запись. Аналогично, режим нельзя изменить с записи только для чтения.

При попытке такого изменения ошибка возбуждается в различных местах в зависимости от платформы.

IO Encoding

При указании ext_enc, считываемые строки будут помечены кодировкой при чтении, а выводимые — преобразуются в указанную кодировку при записи.

При указании ext_enc и int_enc, вводимые строки будут преобразовываться из ext_enc в int_enc при вводе, а выводимые — из int_enc в ext_enc при выводе. См. Encoding для получения более подробной информации о преобразовании при вводе и выводе.

Если используются «BOM|UTF-8», «BOM|UTF-16LE» или «BOM|UTF16-BE», Ruby проверяет BOM Unicode в входном документе, чтобы определить кодировку. Для кодировок UTF-16 режим открытия файла должен быть двоичным. При наличии BOM он удаляется, и используется внешняя кодировка из BOM. При отсутствии BOM используется указанная кодировка Unicode как ext_enc. (Вариант кодирования с BOM нечувствителен к регистру, поэтому «bom|utf-8» также допустимо.)

Параметры

opt может использоваться вместо mode для повышения читаемости. Поддерживаются следующие ключи:

:mode

То же, что и параметр mode

:flags

Устанавливает флаги открытия файла как целое число. Если указан параметр mode, этот параметр будет побитовым ИЛИ.

:external_encoding

Внешняя кодировка для IO.

:internal_encoding

Внутренняя кодировка для IO. «-» — синоним для значения по умолчанию внутренней кодировки.

Если значение равно nil, преобразование не происходит.

:encoding

Устанавливает внешнюю и внутреннюю кодировки как «extern:intern».

:textmode

Если значение истинно, то же, что и «t» в аргументе mode.

:binmode

Если значение истинно, то же, что и «b» в аргументе mode.

:autoclose

Если значение false, fd будет оставаться открытым после завершения работы этого экземпляра IO.

Также, opt может содержать те же ключи, что и в String#encode для управления преобразованием между внешней и внутренней кодировкой.

Пример 1

fd = IO.sysopen("/dev/tty", "w")
a = IO.new(fd,"w")
$stderr.puts "Hello"
a.puts "World"

Вывод:

Hello
World

Пример 2

require 'fcntl'

fd = STDERR.fcntl(Fcntl::F_DUPFD)
io = IO.new(fd, mode: 'w:UTF-16LE', cr_newline: true)
io.puts "Hello, World!"

fd = STDERR.fcntl(Fcntl::F_DUPFD)
io = IO.new(fd, mode: 'w', cr_newline: true,
            external_encoding: Encoding::UTF_16LE)
io.puts "Hello, World!"

Оба примера выводят «Привет, мир!» в UTF-16LE в стандартный вывод ошибок с преобразованием EOL, сгенерированным puts, в CR.

open(fd, mode="r" [, opt]) → io Показать исходный код
open(fd, mode="r" [, opt]) {|io| block } → obj
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;
}

Без связанного блока, IO.open является синонимом для IO.new. Если задан необязательный блок кода, он будет передан io в качестве аргумента, и объект IO будет автоматически закрыт по завершении блока. В этом случае, IO.open возвращает значение блока.

См. IO.new для описания параметров fd, mode и opt.

pipe → [read_io, write_io] Показать исходный код
pipe(ext_enc) → [read_io, write_io]
pipe("ext_enc:int_enc" [, opt]) → [read_io, write_io]
pipe(ext_enc, int_enc [, opt]) → [read_io, write_io]
pipe(...) {|read_io, write_io| ... }
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) && v1 == Qnil) {
        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 defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
    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;
}

Создаёт пару конечных точек канала (соединённых друг с другом) и возвращает их в виде массива из двух элементов объектов IO: [ read_io, write_io ].

Если задан блок, блок вызывается и возвращает значение блока. read_io и write_io передаются блоку в качестве аргументов. Если read_io и write_io не закрыты при завершении блока, они закрываются. То есть закрытие read_io и/или write_io не вызывает ошибки.

Недоступно на всех платформах.

Если в качестве необязательного аргумента указано кодирование (имя кодирования или объект кодирования), строка, считанная из канала, помечается указанной кодировкой. Если аргументом является строка с двумя именами кодирования, разделёнными двоеточием “A:B”, то строка читается из канала, преобразуется из кодировки A (внешняя кодировка) в кодировку B (внутренняя кодировка), а затем помечается кодировкой B. Если указаны два необязательных аргумента, они должны быть объектами или именами кодировок, при этом первый — внешняя кодировка, а второй — внутренняя кодировка. Если указаны внешняя и внутренняя кодировки, необязательный аргумент типа хэш задаёт параметры преобразования.

В примере ниже два процесса закрывают концы канала, которыми не пользуются. Это не просто косметическая мера. Конец канала для чтения не будет генерировать условие конца файла, если есть какие-либо пишущие процессы, которые по-прежнему открыты. В случае родительского процесса rd.read никогда не вернётся, если он не вызовет 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

выводит:

Sending message to parent
Parent got: <Hi Dad>
popen([env,] cmd, mode="r" [, opt]) → io Показать исходный код
popen([env,] cmd, mode="r" [, opt]) {|io| block } → obj
static VALUE
rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
{
    const char *modestr;
    VALUE pname, pmode = Qnil, port, tmp, opt = Qnil, env = Qnil, execarg_obj = Qnil;
    int oflags, fmode;
    convconfig_t convconfig;

    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);
        }
    }

    tmp = rb_check_array_type(pname);
    if (!NIL_P(tmp)) {
        long len = RARRAY_LEN(tmp);
#if SIZEOF_LONG > SIZEOF_INT
        if (len > INT_MAX) {
            rb_raise(rb_eArgError, "too many arguments");
        }
#endif
        execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
        RB_GC_GUARD(tmp);
    }
    else {
        SafeStringValue(pname);
        execarg_obj = Qnil;
        if (!is_popen_fork(pname))
            execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
    }
    if (!NIL_P(execarg_obj)) {
        if (!NIL_P(opt))
            opt = rb_execarg_extract_options(execarg_obj, opt);
        if (!NIL_P(env))
            rb_execarg_setenv(execarg_obj, env);
    }
    rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
    modestr = rb_io_oflags_modestr(oflags);

    port = pipe_open(execarg_obj, modestr, fmode, &convconfig);
    if (NIL_P(port)) {
        /* child */
        if (rb_block_given_p()) {
            rb_yield(Qnil);
            rb_io_flush(rb_stdout);
            rb_io_flush(rb_stderr);
            _exit(0);
        }
        return Qnil;
    }
    RBASIC_SET_CLASS(port, klass);
    if (rb_block_given_p()) {
        return rb_ensure(rb_yield, port, pipe_close, port);
    }
    return port;
}

Запускает указанную команду как дочерний процесс; стандартный ввод и вывод дочернего процесса будут соединены с возвращаемым объектом IO.

ИД процесса, запущенного процесса, можно получить с помощью метода IO#pid.

cmd — это строка или массив следующим образом.

cmd:
  "-"                                      : fork
  commandline                              : command line string which is passed to a shell
  [env, cmdname, arg1, ..., opts]          : command name and zero or more arguments (no shell)
  [env, [cmdname, argv0], arg1, ..., opts] : command name, argv[0] and zero or more arguments (no shell)
(env and opts are optional.)

Если cmd является строкой “-”, то запускается новый экземпляр Ruby как дочерний процесс.

Если cmd является массивом String, то он будет использован в качестве argv дочернего процесса, минуя оболочку. Массив может содержать хэш для переменных окружения и хэш для параметров, аналогично методу spawn.

По умолчанию режим для нового объекта файла — “r”, но mode может быть установлен на любой из режимов, перечисленных в описании класса IO. Последний аргумент opt квалифицирует mode.

# 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
# spawn option.  See the document of Kernel.spawn.
IO.popen(["ls", "/", :err=>[:child, :out]]) {|ls_io|
  ls_result_with_error = ls_io.read
}

# spawn options can be mixed with IO options
IO.popen(["ls", "/"], :err=>[:child, :out]) {|ls_io|
  ls_result_with_error = ls_io.read
}

Возбуждает исключения, которые возбуждаются методами IO.pipe и Kernel.spawn.

Если задан блок, Ruby запустит команду как дочерний процесс, подключённый к Ruby через канал. Конец канала Ruby будет передан в качестве параметра блоку. По завершении блока Ruby закроет канал и установит $?. В этом случае IO.popen возвращает значение блока.

Если блок задан с cmd "-", блок будет выполняться в двух отдельных процессах: один в родительском, другой в дочернем. Родительский процесс получит объект канала в качестве параметра блоку, дочерний вариант блока получит nil, а стандартный ввод и вывод дочернего процесса будут соединены с родительским через канал. Недоступно на всех платформах.

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
}

выводит:

["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;
read(name, [length [, offset]] [, opt] ) → string Показать исходный код
static VALUE
rb_io_s_read(int argc, VALUE *argv, VALUE io)
{
    VALUE opt, offset;
    struct foreach_arg arg;

    argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
    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);
}

Открывает файл, при необходимости переходит к указанной offset, затем возвращает length байт (по умолчанию — остаток файла). read гарантирует, что файл будет закрыт перед возвращением.

Если name начинается с символа канала ("|"), создаётся дочерний процесс так же, как и в Kernel#open, и его вывод возвращается.

Параметры

Хэш параметров принимает следующие ключи:

:encoding

строка или кодировка

Устанавливает кодировку считанной строки. :encoding будет проигнорирован, если указан length. См. Encoding.aliases для возможных кодировок.

:mode

строка или целое число

Задаёт аргумент mode для open(). Он должен начинаться с “r”, иначе это приведёт к ошибке. См. IO.new для списка возможных режимов.

:open_args

массив

Задаёт аргументы для open() в виде массива. Этот ключ не может использоваться в сочетании с :encoding или :mode.

Примеры:

IO.read("testfile")              #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
IO.read("testfile", 20)          #=> "This is line one\nThi"
IO.read("testfile", 20, 10)      #=> "ne one\nThis is line "
IO.read("binfile", mode: "rb")   #=> "\xF7\x00\x00\x0E\x12"
readlines(name, sep=$/ [, getline_args, open_args]) → array Показать исходный код
readlines(name, limit [, getline_args, open_args]) → array
readlines(name, sep, limit [, getline_args, open_args]) → array
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, "13:", NULL, 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);
}

Считывает весь файл, заданный name, в виде отдельных строк и возвращает эти строки в массиве. Строки разделяются символом sep.

a = IO.readlines("testfile")
a[0]   #=> "This is line one\n"

b = IO.readlines("testfile", chomp: true)
b[0]   #=> "This is line one"

Если последний аргумент — хэш, это ключевые аргументы для open.

Параметры для getline

Хэш параметров принимает следующие ключи:

:chomp

Если необязательный ключевой аргумент chomp имеет значение true, \n, \r, и \r\n будут удалены с конца каждой строки.

См. также IO.read для подробностей об open_args.

select(read_array [, write_array [, error_array [, timeout]]]) → array or nil Показать исходный код
static VALUE
rb_f_select(int argc, VALUE *argv, VALUE obj)
{
    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);
}

Вызывает системный вызов select(2). Он отслеживает заданные массивы объектов IO, ожидает, пока один или несколько объектов IO не будут готовы к чтению, готовы к записи или имеют ожидающие исключения соответственно, и возвращает массив, содержащий массивы этих объектов IO. Он вернёт nil если необязательное значение timeout задано и ни один объект IO не готов в течение timeout секунд.

IO.select просматривает буфер объектов IO для проверки возможности чтения. Если буфер IO не пустой, IO.select немедленно сообщает о возможности чтения. Эта «проверка» происходит только для объектов IO. Она не происходит для объектов, подобных IO, таких как OpenSSL::SSL::SSLSocket.

Лучший способ использовать IO.select — вызывать его после неблокирующих методов, таких как read_nonblock, write_nonblock и т. д. Методы поднимают исключение, которое расширено IO::WaitReadable или IO::WaitWritable. Модули сообщают, как вызывающей стороне следует ждать с помощью IO.select. Если поднято исключение IO::WaitReadable, вызывающая сторона должна ждать чтения. Если поднято исключение IO::WaitWritable, вызывающая сторона должна ждать записи.

Таким образом, блокирующее чтение (readpartial) можно эмулировать с помощью read_nonblock и IO.select следующим образом:

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

В особенности, сочетание неблокирующих методов и IO.select предпочтительно для объектов типа IO, таких как OpenSSL::SSL::SSLSocket. У него есть метод to_io для возвращения базового объекта IO. IO.select вызывает to_io для получения дескриптора файла для ожидания.

Это означает, что уведомление о возможности чтения IO.select не означает возможность чтения из объекта OpenSSL::SSL::SSLSocket.

Наиболее вероятная ситуация — это то, что OpenSSL::SSL::SSLSocket буферирует некоторые данные. IO.select не видит буфер. Поэтому IO.select может заблокироваться, когда OpenSSL::SSL::SSLSocket#readpartial не блокируется.

Однако существуют и другие более сложные ситуации.

SSL — это протокол, который представляет собой последовательность записей. Запись состоит из нескольких байтов. Таким образом, удалённая сторона SSL отправляет частичную запись, IO.select сообщает о возможности чтения, но OpenSSL::SSL::SSLSocket не может расшифровать байт, и OpenSSL::SSL::SSLSocket#readpartial заблокируется.

Также удалённая сторона может запросить переподключение SSL, что заставляет локальный движок SSL записать некоторые данные. Это означает, что OpenSSL::SSL::SSLSocket#readpartial может вызвать системный вызов write, и он может заблокироваться. В такой ситуации OpenSSL::SSL::SSLSocket#read_nonblock поднимает IO::WaitWritable вместо блокировки. Следовательно, вызывающая сторона должна ждать готовности к записи, как показано в примере выше.

Сочетание неблокирующих методов и IO.select также полезно для потоков, таких как tty, сокеты-каналы, когда несколько процессов считывают данные из потока.

Наконец, разработчики ядра Linux не гарантируют, что возможность чтения в select(2) означает возможность чтения в последующем read(2), даже для одного процесса. См. руководство select(2) в системе GNU/Linux.

Вызов IO.select перед IO#readpartial работает хорошо, как обычно. Однако это не лучший способ использования IO.select.

Уведомление о возможности записи select(2) не показывает, сколько байтов можно записать. Метод IO#write блокируется до тех пор, пока вся строка не будет записана. Поэтому IO#write(two or more bytes) может заблокироваться после уведомления о возможности записи IO.select. Требуется IO#write_nonblock для предотвращения блокировки.

Блокирующая запись (write) можно эмулировать с помощью write_nonblock и IO.select следующим образом: IO::WaitReadable также нужно перехватывать для переподключения SSL в 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

Параметры

read_array

массив объектов IO, которые ожидают готовности к чтению

write_array

массив объектов IO, которые ожидают готовности к записи

error_array

массив объектов IO, которые ожидают исключений

timeout

числовое значение во секундах

Пример

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
}

выводит:

ping pong
ping pong
ping pong
(snipped)
ping
sysopen(path, [mode, [perm]]) → integer Показать исходный код
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);
}

Открывает указанный путь, возвращая базовый дескриптор файла как Integer.

IO.sysopen("testfile")   #=> 3
try_convert(obj) → io or nil Показать исходный код
static VALUE
rb_io_s_try_convert(VALUE dummy, VALUE io)
{
    return rb_io_check_io(io);
}

Пытается преобразовать obj в объект IO с помощью метода to_io. Возвращает преобразованный объект IO или nil если obj не может быть преобразован по какой-либо причине.

IO.try_convert(STDOUT)     #=> STDOUT
IO.try_convert("STDOUT")   #=> nil

require 'zlib'
f = open("/tmp/zz.gz")       #=> #<File:/tmp/zz.gz>
z = Zlib::GzipReader.open(f) #=> #<Zlib::GzipReader:0x81d8744>
IO.try_convert(z)            #=> #<File:/tmp/zz.gz>
write(name, string [, offset]) → integer Показать исходный код
write(name, string [, offset] [, opt]) → integer
static VALUE
rb_io_s_write(int argc, VALUE *argv, VALUE io)
{
    return io_s_write(argc, argv, io, 0);
}

Открывает файл, при необходимости ищет с заданным offset, записывает string, затем возвращает записанную длину. write гарантирует закрытие файла перед возвратом. Если offset не указан в режиме записи, файл обрезается. В противном случае он не обрезается.

IO.write("testfile", "0123456789", 20)  #=> 10
# File could contain:  "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n"
IO.write("testfile", "0123456789")      #=> 10
# File would now read: "0123456789"

Если последний аргумент — хэш, он задаёт параметры для внутреннего open(). Он принимает следующие ключи:

:encoding

строка или кодировка

Указывает кодировку вводимой строки. См. Encoding.aliases для возможных кодировок.

:mode

строка или целое число

Указывает аргумент mode для open(). Он должен начинаться с «w», «a» или «r+», в противном случае возникнет ошибка. См. IO.new для списка возможных режимов.

:perm

целое число

Указывает аргумент perm для open().

:open_args

массив

Указывает аргументы для open() в виде массива. Этот ключ нельзя использовать совместно с другими ключами.

Публичные методы экземпляра

ios << obj → ios Показать исходный код
VALUE
rb_io_addstr(VALUE io, VALUE str)
{
    rb_io_write(io, str);
    return io;
}

String Вывод—Записывает obj в ios. obj будет преобразован в строку с использованием to_s.

$stdout << "Hello " << "world!\n"

результат:

Hello world!
advise(advice, offset=0, len=0) → nil Показать исходный код
static VALUE
rb_io_advise(int argc, VALUE *argv, VALUE io)
{
    VALUE advice, offset, len;
    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
}

Объявить намерение получить доступ к данным из текущего файла по определённой схеме. На платформах, которые не поддерживают системный вызов posix_fadvise(2), этот метод ничего не делает.

advice — один из следующих символов:

:normal

Нет рекомендаций; предполагается по умолчанию для открытого файла.

:sequential

К данным будет осуществляться последовательный доступ, причём меньшие смещения будут считываться раньше больших.

:random

К данным будет осуществляться доступ в произвольном порядке.

:willneed

К данным будет осуществлён доступ в ближайшем будущем.

:dontneed

К данным не будет осуществлён доступ в ближайшем будущем.

:noreuse

К данным будет осуществлён доступ только один раз.

Семантика рекомендации зависит от платформы. Подробнее см. man 2 posix_fadvise.

«данные» означают область текущего файла, которая начинается со смещения и простирается на len байт. Если len равно 0, область заканчивается последним байтом файла. По умолчанию и offset, и len равны 0, что означает, что рекомендация применяется ко всему файлу.

При возникновении ошибки будет выброшено одно из следующих исключений:

IOError

Поток IO закрыт.

Errno::EBADF

Дескриптор файла текущего файла недействителен.

Errno::EINVAL

Указано недопустимое значение для advice.

Errno::ESPIPE

Дескриптор файла текущего файла ссылается на FIFO или канал. (Linux в этом случае выдает Errno::EINVAL).

TypeError

advice не является Symbol, или один из других аргументов не является Integer.

RangeError

Один из указанных аргументов слишком большой/маленький.

Этот список не является исчерпывающим; возможны и другие исключения Errno

исключения.

autoclose = bool → true or false Показать исходный код
static VALUE
rb_io_set_autoclose(VALUE io, VALUE autoclose)
{
    rb_io_t *fptr;
    GetOpenFile(io, fptr);
    if (!RTEST(autoclose))
        fptr->mode |= FMODE_PREP;
    else
        fptr->mode &= ~FMODE_PREP;
    return autoclose;
}

Устанавливает флаг автоматического закрытия.

f = open("/dev/null")
IO.for_fd(f.fileno)
# ...
f.gets # may cause Errno::EBADF

f = open("/dev/null")
IO.for_fd(f.fileno).autoclose = false
# ...
f.gets # won't cause Errno::EBADF
autoclose? → true or false Показать исходный код
static VALUE
rb_io_autoclose_p(VALUE io)
{
    rb_io_t *fptr = RFILE(io)->fptr;
    rb_io_check_closed(fptr);
    return (fptr->mode & FMODE_PREP) ? Qfalse : Qtrue;
}

Возвращает true если базовый дескриптор файла ios будет автоматически закрыт при его завершении, в противном случае false.

beep() Показать исходный код
static VALUE
console_beep(VALUE io)
{
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetWriteFD(fptr);
#ifdef _WIN32
    (void)fd;
    MessageBeep(0);
#else
    if (write(fd, "\a", 1) < 0)
        rb_sys_fail(0);
#endif
    return io;
}
binmode → ios Показать исходный код
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;
}

Переводит ios в бинарный режим. После того, как поток находится в бинарном режиме, его нельзя перевести обратно в небинарный режим.

  • преобразование символов новой строки отключено

  • преобразование кодировки отключено

  • содержимое обрабатывается как ASCII-8BIT

binmode? → true or false Показать исходный код
static VALUE
rb_io_binmode_p(VALUE io)
{
    rb_io_t *fptr;
    GetOpenFile(io, fptr);
    return fptr->mode & FMODE_BINMODE ? Qtrue : Qfalse;
}

Возвращает true если ios находится в binmode.

bytes() Показать исходный код
static VALUE
rb_io_bytes(VALUE io)
{
    rb_warn_deprecated("IO#bytes", "#each_byte");
    if (!rb_block_given_p())
        return rb_enumeratorize(io, ID2SYM(rb_intern("each_byte")), 0, 0);
    return rb_io_each_byte(io);
}

Это устаревшее псевдоним для each_byte.

chars() Показать исходный код
static VALUE
rb_io_chars(VALUE io)
{
    rb_warn_deprecated("IO#chars", "#each_char");
    if (!rb_block_given_p())
        return rb_enumeratorize(io, ID2SYM(rb_intern("each_char")), 0, 0);
    return rb_io_each_char(io);
}

Это устаревшее псевдоним для each_char.

check_winsize_changed() Показать исходный код
static VALUE
console_check_winsize_changed(VALUE io)
{
    rb_io_t *fptr;
    HANDLE h;
    DWORD num;

    GetOpenFile(io, fptr);
    h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(fptr));
    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;
}
clear_screen() Показать исходный код
static VALUE
console_clear_screen(VALUE io)
{
    console_erase_screen(io, INT2FIX(2));
    console_goto(io, INT2FIX(0), INT2FIX(0));
    return io;
}
close → nil Показать исходный код
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;
}

Закрывает ios и очищает все ожидающие записи в операционную систему. Поток становится недоступен для любых дальнейших операций с данными; если будет предпринята такая попытка, будет выброшено исключение IOError. Потоки ввода-вывода автоматически закрываются, когда они запрашиваются сборщиком мусора.

Если ios открыт с помощью IO.popen, close устанавливает $?.

Вызов этого метода для закрытого объекта IO просто игнорируется, начиная с Ruby 2.3.

close_on_exec = bool → true or false Показать исходный код
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;
}

Устанавливает флаг close-on-exec.

f = open("/dev/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 по умолчанию устанавливает флаги close-on-exec для всех дескрипторов файлов, начиная с Ruby 2.0.0. Поэтому вам не нужно устанавливать его самостоятельно. Кроме того, сброс флага close-on-exec может привести к утечке дескриптора файла, если другой поток использует fork() и exec() (например, через метод system()). Если вам действительно необходимо наследование дескриптора файла дочерним процессом, используйте аргумент spawn(), например, fd=>fd.

close_on_exec? → true or false Показать исходный код
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;
}

Возвращает true если ios будет закрыт при exec.

f = open("/dev/null")
f.close_on_exec?                 #=> false
f.close_on_exec = true
f.close_on_exec?                 #=> true
f.close_on_exec = false
f.close_on_exec?                 #=> false
close_read → nil Показать исходный код
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);
}

Закрывает входной конец дуплексного потока ввода-вывода (т. е. потока, содержащего как входной, так и выходной поток, например, канал). Вызовет исключение IOError, если поток не является дуплексным.

f = IO.popen("/bin/sh","r+")
f.close_read
f.readlines

результат:

prog.rb:3:in `readlines': not opened for reading (IOError)
 from prog.rb:3

Вызов этого метода для закрытого объекта IO просто игнорируется, начиная с Ruby 2.3.

close_write → nil Показать исходный код
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;
}

Закрывает выходной конец дуплексного потока ввода-вывода (т. е. потока, содержащего как входной, так и выходной поток, например, канал). Вызовет исключение IOError, если поток не является дуплексным.

f = IO.popen("/bin/sh","r+")
f.close_write
f.print "nowhere"

результат:

prog.rb:3:in `write': not opened for writing (IOError)
 from prog.rb:3:in `print'
 from prog.rb:3

Вызов этого метода для закрытого объекта IO просто игнорируется, начиная с Ruby 2.3.

closed? → true or false Показать исходный код
static VALUE
rb_io_closed(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 0 <= fptr->fd ? Qfalse : Qtrue;
}

Возвращает true если ios полностью закрыт (для дуплексных потоков — как устройство чтения, так и записи), false в противном случае.

f = File.new("testfile")
f.close         #=> nil
f.closed?       #=> true
f = IO.popen("/bin/sh","r+")
f.close_write   #=> nil
f.closed?       #=> false
f.close_read    #=> nil
f.closed?       #=> true
codepoints() Показать исходный код
static VALUE
rb_io_codepoints(VALUE io)
{
    rb_warn_deprecated("IO#codepoints", "#each_codepoint");
    if (!rb_block_given_p())
        return rb_enumeratorize(io, ID2SYM(rb_intern("each_codepoint")), 0, 0);
    return rb_io_each_codepoint(io);
}

Это устаревшее псевдоним для each_codepoint.

console_mode → mode Показать исходный код
static VALUE
console_conmode_get(VALUE io)
{
    conmode t;
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!getattr(fd, &t)) rb_sys_fail(0);

    return conmode_new(cConmode, &t);
}

Возвращает данные, представляющие текущий режим консоли.

Для использования этого метода необходимо выполнить require 'io/console'.

console_mode = mode Показать исходный код
static VALUE
console_conmode_set(VALUE io, VALUE mode)
{
    conmode *t, r;
    rb_io_t *fptr;
    int fd;

    TypedData_Get_Struct(mode, conmode, &conmode_type, t);
    r = *t;
    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!setattr(fd, &r)) rb_sys_fail(0);

    return mode;
}

Устанавливает режим консоли в mode.

Для использования этого метода необходимо выполнить require 'io/console'.

cooked {|io| } Показать исходный код
static VALUE
console_cooked(VALUE io)
{
    return ttymode(io, rb_yield, io, set_cookedmode, NULL);
}

Вызывает блок в режиме cooked.

STDIN.cooked(&:gets)

будет читать и возвращать строку с отображением и редактированием строк.

Для использования этого метода необходимо выполнить require 'io/console'.

cooked! Показать исходный код
static VALUE
console_set_cooked(VALUE io)
{
    conmode t;
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!getattr(fd, &t)) rb_sys_fail(0);
    set_cookedmode(&t, NULL);
    if (!setattr(fd, &t)) rb_sys_fail(0);
    return io;
}

Включает режим cooked.

Если требуется вернуть режим терминала, используйте io.cooked { … }.

Для использования этого метода необходимо выполнить require 'io/console'.

cursor() Показать исходный код
static VALUE
console_cursor_pos(VALUE io)
{
    rb_io_t *fptr;
    int fd;
    rb_console_size_t ws;

    GetOpenFile(io, fptr);
    fd = GetWriteFD(fptr);
    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));
}
cursor=(p1) Показать исходный код
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));
}
cursor_down(p1) Показать исходный код
static VALUE
console_cursor_down(VALUE io, VALUE val)
{
    return console_move(io, +NUM2INT(val), 0);
}
cursor_left(p1) Показать исходный код
static VALUE
console_cursor_left(VALUE io, VALUE val)
{
    return console_move(io, 0, -NUM2INT(val));
}
cursor_right(p1) Показать исходный код
static VALUE
console_cursor_right(VALUE io, VALUE val)
{
    return console_move(io, 0, +NUM2INT(val));
}
cursor_up(p1) Показать исходный код
static VALUE
console_cursor_up(VALUE io, VALUE val)
{
    return console_move(io, -NUM2INT(val), 0);
}
each(sep=$/ [, getline_args]) {|line| block } → ios Показать исходный код
each(limit [, getline_args]) {|line| block } → ios
each(sep, limit [, getline_args]) {|line| block } → ios
each(...) → an_enumerator
each_line(sep=$/ [, getline_args]) {|line| block } → ios
each_line(limit [, getline_args]) {|line| block } → ios
each_line(sep, limit [, getline_args]) {|line| block } → ios
each_line(...) → an_enumerator
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;
}

Выполняет блок для каждой строки в ios, где строки разделены sep. ios должен быть открыт для чтения, иначе будет вызвано IOError.

Если блок не задан, вместо него возвращается итератор.

f = File.new("testfile")
f.each {|line| puts "#{f.lineno}: #{line}" }

выводит:

1: This is line one
2: This is line two
3: This is line three
4: And so on...

См. IO.readlines для получения информации о getline_args.

each_byte {|byte| block } → ios Показать исходный код
each_byte → an_enumerator
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));
            errno = 0;
        }
        rb_io_check_byte_readable(fptr);
        READ_CHECK(fptr);
    } while (io_fillbuf(fptr) >= 0);
    return io;
}

Вызывает предоставленный блок один раз для каждого байта (0..255) в ios, передавая байт в качестве аргумента. Поток должен быть открыт для чтения, иначе будет вызвано IOError.

Если блок не задан, вместо него возвращается итератор.

f = File.new("testfile")
checksum = 0
f.each_byte {|x| checksum ^= x }   #=> #<File:testfile>
checksum                           #=> 12
each_char {|c| block } → ios Показать исходный код
each_char → an_enumerator
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;
}

Вызывает предоставленный блок один раз для каждого символа в ios, передавая символ в качестве аргумента. Поток должен быть открыт для чтения, иначе будет вызвано IOError.

Если блок не задан, вместо него возвращается итератор.

f = File.new("testfile")
f.each_char {|c| print c, ' ' }   #=> #<File:testfile>
each_codepoint {|c| block } → ios Показать исходный код
codepoints {|c| block } → ios
each_codepoint → an_enumerator
codepoints → an_enumerator
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));
        }
    }
    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)) {
          invalid:
            rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
        }
        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;
        }
    }
    return io;
}

Передает порядковый номер Integer каждого символа в ios, передавая код символа в качестве аргумента. Поток должен быть открыт для чтения, иначе будет вызвано IOError.

Если блок не задан, вместо него возвращается итератор.

each_line(sep=$/ [, getline_args]) {|line| block } → ios Показать исходный код
each_line(limit [, getline_args]) {|line| block } → ios
each_line(sep, limit [, getline_args]) {|line| block } → ios
each_line(...) → an_enumerator
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;
}

Выполняет блок для каждой строки в ios, где строки разделены sep. ios должен быть открыт для чтения, иначе будет вызвано IOError.

Если блок не задан, вместо него возвращается итератор.

f = File.new("testfile")
f.each {|line| puts "#{f.lineno}: #{line}" }

выводит:

1: This is line one
2: This is line two
3: This is line three
4: And so on...

См. IO.readlines для получения информации о getline_args.

echo = flag Показать исходный код
static VALUE
console_set_echo(VALUE io, VALUE f)
{
    conmode t;
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!getattr(fd, &t)) rb_sys_fail(0);
    if (RTEST(f))
        set_echo(&t, NULL);
    else
        set_noecho(&t, NULL);
    if (!setattr(fd, &t)) rb_sys_fail(0);
    return io;
}

Включает/выключает отображение символов на экране. На некоторых платформах не все сочетания этих флагов и режимов raw/cooked могут быть валидны.

Для использования этого метода необходимо выполнить require 'io/console'.

echo? → true or false Показать исходный код
static VALUE
console_echo_p(VALUE io)
{
    conmode t;
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!getattr(fd, &t)) rb_sys_fail(0);
    return echo_p(&t) ? Qtrue : Qfalse;
}

Возвращает true, если отображение символов включено.

Для использования этого метода необходимо выполнить require 'io/console'.

END_OF_DOCUMENT_MARKER
eof → true или false Показать исходный код
eof? → true или false
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 defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
    if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
        return eof(fptr->fd) ? Qtrue : Qfalse;
    }
#endif
    if (io_fillbuf(fptr) < 0) {
        return Qtrue;
    }
    return Qfalse;
}

Возвращает true, если ios находится в конце файла, то есть больше нет данных для чтения. Поток должен быть открыт для чтения, иначе будет вызвано исключение IOError.

f = File.new("testfile")
dummy = f.readlines
f.eof   #=> true

Если ios — это поток, такой как pipe или socket, IO#eof? блокируется до тех пор, пока другой конец не отправит данные или не закроет его.

r, w = IO.pipe
Thread.new { sleep 1; w.close }
r.eof?  #=> true after 1 second blocking

r, w = IO.pipe
Thread.new { sleep 1; w.puts "a" }
r.eof?  #=> false after 1 second blocking

r, w = IO.pipe
r.eof?  # blocks forever

Обратите внимание, что IO#eof? считывает данные в буфер входного байта. Поэтому IO#sysread может работать не так, как ожидается, с IO#eof?, если вы не вызовете IO#rewind сначала (что недоступно для некоторых потоков).

eof? → true или false Показать исходный код
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 defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
    if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
        return eof(fptr->fd) ? Qtrue : Qfalse;
    }
#endif
    if (io_fillbuf(fptr) < 0) {
        return Qtrue;
    }
    return Qfalse;
}

Возвращает true, если ios находится в конце файла, то есть больше нет данных для чтения. Поток должен быть открыт для чтения, иначе будет вызвано исключение IOError.

f = File.new("testfile")
dummy = f.readlines
f.eof   #=> true

Если ios — это поток, такой как pipe или socket, IO#eof? блокируется до тех пор, пока другой конец не отправит данные или не закроет его.

r, w = IO.pipe
Thread.new { sleep 1; w.close }
r.eof?  #=> true after 1 second blocking

r, w = IO.pipe
Thread.new { sleep 1; w.puts "a" }
r.eof?  #=> false after 1 second blocking

r, w = IO.pipe
r.eof?  # blocks forever

Обратите внимание, что IO#eof? считывает данные в буфер входного байта. Поэтому IO#sysread может работать не так, как ожидается, с IO#eof?, если вы не вызовете IO#rewind сначала (что недоступно для некоторых потоков).

erase_line(p1) Показать исходный код
static VALUE
console_erase_line(VALUE io, VALUE val)
{
    rb_io_t *fptr;
    HANDLE h;
    rb_console_size_t ws;
    COORD *pos = &ws.dwCursorPosition;
    DWORD w;
    int mode = mode_in_range(val, 2, "line erase");

    GetOpenFile(io, fptr);
    h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
    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;
}
erase_screen(p1) Показать исходный код
static VALUE
console_erase_screen(VALUE io, VALUE val)
{
    rb_io_t *fptr;
    HANDLE h;
    rb_console_size_t ws;
    COORD *pos = &ws.dwCursorPosition;
    DWORD w;
    int mode = mode_in_range(val, 3, "screen erase");

    GetOpenFile(io, fptr);
    h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
    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);
    return io;
}
IO#expect(pattern,timeout=9999999) → Массив Показать исходный код
IO#expect(pattern,timeout=9999999) { |result| ... } → nil
# File 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

Считывает из IO до тех пор, пока заданный pattern не будет совпадать или не закончится timeout.

Возвращает массив с буфером чтения, за которым следуют совпадения. Если задан блок, результат передается в блок, и возвращается nil.

При вызове без блока он ждет, пока вход, который соответствует заданному pattern, не будет получен из IO или не истечет время, указанное в качестве таймаута. Массив возвращается, когда шаблон получен из IO. Первый элемент массива — это вся строка, полученная из IO до совпадения шаблона, за которым следуют элементы, указывающие, к какому якорю в регулярном выражении сопоставляется шаблон.

Необязательный параметр таймаута определяет общее время ожидания шаблона в секундах. Если таймаут истечет или будет обнаружен eof, возвращается или передается nil. Однако буфер в сессии таймаута сохраняется для следующего вызова expect. Значение по умолчанию для таймаута составляет 9999999 секунд.

external_encoding → кодировка Показать исходный код
static VALUE
rb_io_external_encoding(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(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));
}

Возвращает объект Encoding, который представляет кодировку файла. Если io находится в режиме записи и кодировка не указана, возвращает nil.

fcntl(integer_cmd, arg) → целое Показать исходный код
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);
}

Предоставляет механизм для выдачи команд низкого уровня для управления или запроса потоков ввода-вывода, ориентированных на файлы. Аргументы и результаты зависят от платформы. Если arg — число, его значение передается непосредственно. Если это строка, она интерпретируется как двоичная последовательность байтов (Array#pack может быть полезным способом создания этой строки). На платформах Unix см. fcntl(2) для получения подробной информации. Не реализовано на всех платформах.

fdatasync → 0 или nil Показать исходный код
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(0);

    if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
        return INT2FIX(0);

    /* fall back */
    return rb_io_fsync(io);
}

Немедленно записывает все данные из буфера в ios на диск.

Если операционная система не поддерживает fdatasync(2), вызывается IO#fsync (что может вызвать NotImplementedError).

fileno → целое Показать исходный код
to_i → целое
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);
}

Возвращает целое число, представляющее числовой дескриптор файла для ios.

$stdin.fileno    #=> 0
$stdout.fileno   #=> 1
Также алиас: to_i
flush → ios Показать исходный код
VALUE
rb_io_flush(VALUE io)
{
    return rb_io_flush_raw(io, 1);
}

Очищает любые данные из буфера в ios в операционной системе (обратите внимание, что это только внутреннее буферирование Ruby; ОС также может буферизовать данные).

$stdout.print "no newline"
$stdout.flush

выводит:

no newline
fsync → 0 или nil Показать исходный код
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(0);
    if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
        rb_sys_fail_path(fptr->pathv);
    return INT2FIX(0);
}

Немедленно записывает все данные из буфера в ios на диск. Обратите внимание, что fsync отличается от использования IO#sync=. Последнее гарантирует, что данные очищаются из буферов Ruby, но не гарантирует, что операционная система фактически запишет их на диск.

NotImplementedError возникает, если операционная система не поддерживает fsync(2).

getbyte → целое или nil Показать исходный код
VALUE
rb_io_getbyte(VALUE io)
{
    rb_io_t *fptr;
    int c;

    GetOpenFile(io, fptr);
    rb_io_check_byte_readable(fptr);
    READ_CHECK(fptr);
    if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(rb_stdout, T_FILE)) {
        rb_io_t *ofp;
        GetOpenFile(rb_stdout, ofp);
        if (ofp->mode & FMODE_TTY) {
            rb_io_flush(rb_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);
}

Получает следующий 8-битный байт (0..255) из ios. Возвращает nil при вызове в конце файла.

f = File.new("testfile")
f.getbyte   #=> 84
f.getbyte   #=> 104
getc → строка или nil Показать исходный код
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);
}

Считывает строку из одного символа из ios. Возвращает nil при вызове в конце файла.

f = File.new("testfile")
f.getc   #=> "h"
f.getc   #=> "e"
getch(min: nil, time: nil, intr: nil) → символ Показать исходный код
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 w, len;
    char buf[8];
    wint_t wbuf[2];
    struct timeval *to = NULL, tv;

    GetOpenFile(io, fptr);
    if (optp) {
        if (optp->vtime) {
            to = &tv;
            tv.tv_sec = optp->vtime / 10;
            tv.tv_usec = (optp->vtime % 10) * 100000;
        }
        if (optp->vmin != 1) {
            rb_warning("min option ignored");
        }
        if (optp->intr) {
            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 {
            rb_warning("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
}

Считывает и возвращает символ в сыром режиме.

См. IO#raw для получения подробной информации о параметрах.

Для использования этого метода необходимо потребовать 'io/console'.

getpass(prompt=nil) → строка Показать исходный код
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);
    str = rb_ensure(getpass_call, io, puts_call, wio);
    return str_chomp(str);
}

Считывает и возвращает строку без отображения на экране. Выводит prompt, если это не nil.

Для использования этого метода необходимо потребовать 'io/console'.

END_OF_DOCUMENT_MARKER
gets(sep=$/ [, getline_args]) → строка или nil Показать исходный код
gets(limit [, getline_args]) → строка или nil
gets(sep, limit [, getline_args]) → строка или nil
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;
}

Читает следующую «строку» из потока ввода-вывода; строки разделены символом sep. Разделитель nil читает всё содержимое, а разделитель нулевой длины читает ввод по абзацам (два последовательных символа новой строки в вводе отделяют абзацы). Поток должен быть открыт для чтения, иначе будет поднято исключение IOError. Прочитанная строка возвращается и также присваивается $_. Возвращает nil при достижении конца файла. Если первый аргумент — целое число, или если указан необязательный второй аргумент, возвращаемая строка не будет длиннее заданного значения в байтах.

File.new("testfile").gets   #=> "This is line one\n"
$_                          #=> "This is line one\n"

File.new("testfile").gets(4)#=> "This"

Если IO содержит многобайтовые символы, то gets(1) возвращает символ целиком:

# Russian characters take 2 bytes
File.write("testfile", "\u{442 435 441 442}")
File.open("testfile") {|f|f.gets(1)} #=> "\u0442"
File.open("testfile") {|f|f.gets(2)} #=> "\u0442"
File.open("testfile") {|f|f.gets(3)} #=> "\u0442\u0435"
File.open("testfile") {|f|f.gets(4)} #=> "\u0442\u0435"
goto(p1, p2) Показать исходный код
static VALUE
console_goto(VALUE io, VALUE y, VALUE x)
{
    rb_io_t *fptr;
    int fd;
    COORD pos;

    GetOpenFile(io, fptr);
    fd = GetWriteFD(fptr);
    pos.X = NUM2UINT(x);
    pos.Y = NUM2UINT(y);
    if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
    return io;
}
goto_column(p1) Показать исходный код
static VALUE
console_goto_column(VALUE io, VALUE val)
{
    rb_io_t *fptr;
    HANDLE h;
    rb_console_size_t ws;
    COORD *pos = &ws.dwCursorPosition;

    GetOpenFile(io, fptr);
    h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
    if (!GetConsoleScreenBufferInfo(h, &ws)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
    pos->X = NUM2INT(val);
    if (!SetConsoleCursorPosition(h, *pos)) {
        rb_syserr_fail(LAST_ERROR, 0);
    }
    return io;
}
iflush Показать исходный код
static VALUE
console_iflush(VALUE io)
{
    rb_io_t *fptr;
    int fd;

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    if (tcflush(fd, TCIFLUSH)) rb_sys_fail(0);
#endif
    (void)fd;
    return io;
}

Очищает буфер ввода в ядре.

Для использования этого метода необходимо подключить модуль 'io/console'.

inspect → строка Показать исходный код
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, ">");
}

Возвращает строку, описывающую объект IO.

internal_encoding → кодировка Показать исходный код
static VALUE
rb_io_internal_encoding(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    if (!fptr->encs.enc2) return Qnil;
    return rb_enc_from_encoding(io_read_encoding(fptr));
}

Возвращает Encoding внутренней строки, если указано преобразование. В противном случае возвращает nil.

ioctl(integer_cmd, arg) → целое число Показать исходный код
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);
}

Предоставляет механизм для отправки низкоуровневых команд для управления или запроса устройств ввода-вывода. Аргументы и результаты зависят от платформы. Если arg — число, его значение передаётся напрямую. Если это строка, она интерпретируется как двоичная последовательность байтов. На платформах Unix, см. ioctl(2) для подробностей. Не реализовано на всех платформах.

ioflush Показать исходный код
static VALUE
console_ioflush(VALUE io)
{
    rb_io_t *fptr;
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    int fd1, fd2;
#endif

    GetOpenFile(io, fptr);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    fd1 = GetReadFD(fptr);
    fd2 = GetWriteFD(fptr);
    if (fd2 != -1 && fd1 != fd2) {
        if (tcflush(fd1, TCIFLUSH)) rb_sys_fail(0);
        if (tcflush(fd2, TCOFLUSH)) rb_sys_fail(0);
    }
    else {
        if (tcflush(fd1, TCIOFLUSH)) rb_sys_fail(0);
    }
#endif
    return io;
}

Очищает буферы ввода и вывода в ядре.

Для использования этого метода необходимо подключить модуль 'io/console'.

isatty → true или false Показать исходный код
static VALUE
rb_io_isatty(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    if (isatty(fptr->fd) == 0)
        return Qfalse;
    return Qtrue;
}

Возвращает true если ios связан с терминальным устройством (tty), false в противном случае.

File.new("testfile").isatty   #=> false
File.new("/dev/tty").isatty   #=> true
lineno → целое число Показать исходный код
static VALUE
rb_io_lineno(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);
    return INT2NUM(fptr->lineno);
}

Возвращает текущий номер строки в ios. Поток должен быть открыт для чтения. lineno считает количество вызовов gets, а не количество встреченных символов новой строки. Эти значения будут отличаться, если gets вызывается с разделителем, отличным от новой строки.

Методы, использующие $/, такие как each, lines и readline, также будут увеличивать lineno.

См. также переменную $..

f = File.new("testfile")
f.lineno   #=> 0
f.gets     #=> "This is line one\n"
f.lineno   #=> 1
f.gets     #=> "This is line two\n"
f.lineno   #=> 2
lineno = целое число → целое число Показать исходный код
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;
}

Вручную устанавливает текущий номер строки на заданное значение. $. обновляется только при следующем чтении.

f = File.new("testfile")
f.gets                     #=> "This is line one\n"
$.                         #=> 1
f.lineno = 1000
f.lineno                   #=> 1000
$.                         #=> 1         # lineno of last read
f.gets                     #=> "This is line two\n"
$.                         #=> 1001      # lineno of last read
lines(*args) Показать исходный код
static VALUE
rb_io_lines(int argc, VALUE *argv, VALUE io)
{
    rb_warn_deprecated("IO#lines", "#each_line");
    if (!rb_block_given_p())
        return rb_enumeratorize(io, ID2SYM(rb_intern("each_line")), argc, argv);
    return rb_io_each_line(argc, argv, io);
}

Это устаревший псевдоним для each_line.

noecho {|io| } Показать исходный код
static VALUE
console_noecho(VALUE io)
{
    return ttymode(io, rb_yield, io, set_noecho, NULL);
}

Возвращает self с отключенным эхом.

STDIN.noecho(&:gets)

будет читать и возвращать строку без эха.

Для использования этого метода необходимо подключить модуль 'io/console'.

nonblock {|io| } → io
nonblock(boolean) {|io| } → io
static VALUE
rb_io_nonblock_block(int argc, VALUE *argv, VALUE io)
{
    int nb = 1;
    rb_io_t *fptr;
    int f, restore[2];

    GetOpenFile(io, fptr);
    if (argc > 0) {
        VALUE v;
        rb_scan_args(argc, argv, "01", &v);
        nb = RTEST(v);
    }
    f = io_nonblock_mode(fptr->fd);
    restore[0] = fptr->fd;
    restore[1] = f;
    if (!io_nonblock_set(fptr->fd, f, nb))
        return rb_yield(io);
    return rb_ensure(rb_yield, io, io_nonblock_restore, (VALUE)restore);
}

Возвращает self в режиме без ожидания.

Когда false передаётся в качестве аргумента, self возвращается в блокирующем режиме. Исходный режим восстанавливается после выполнения блока.

nonblock = boolean → boolean Показать исходный код
static VALUE
rb_io_nonblock_set(VALUE io, VALUE nb)
{
    rb_io_t *fptr;
    GetOpenFile(io, fptr);
    if (RTEST(nb))
        rb_io_set_nonblock(fptr);
    else
        io_nonblock_set(fptr->fd, io_nonblock_mode(fptr->fd), RTEST(nb));
    return io;
}

Включает режим без ожидания для потока, когда установлено значение true, и блокирующий режим, когда установлено значение false.

nonblock? → boolean Показать исходный код
static VALUE
rb_io_nonblock_p(VALUE io)
{
    rb_io_t *fptr;
    GetOpenFile(io, fptr);
    if (io_nonblock_mode(fptr->fd) & O_NONBLOCK)
        return Qtrue;
    return Qfalse;
}

Возвращает true если объект IO находится в режиме без ожидания.

nread → int Показать исходный код
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);
    if (!FIONREAD_POSSIBLE_P(fptr->fd)) return INT2FIX(0);
    if (ioctl(fptr->fd, FIONREAD, &n)) return INT2FIX(0);
    if (n > 0) return ioctl_arg2num(n);
    return INT2FIX(0);
}

Возвращает количество байтов, которые могут быть прочитаны без блокировки. Возвращает ноль, если информация недоступна.

oflush Показать исходный код
static VALUE
console_ioflush(VALUE io)
{
    rb_io_t *fptr;
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    int fd1, fd2;
#endif

    GetOpenFile(io, fptr);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
    fd1 = GetReadFD(fptr);
    fd2 = GetWriteFD(fptr);
    if (fd2 != -1 && fd1 != fd2) {
        if (tcflush(fd1, TCIFLUSH)) rb_sys_fail(0);
        if (tcflush(fd2, TCOFLUSH)) rb_sys_fail(0);
    }
    else {
        if (tcflush(fd1, TCIOFLUSH)) rb_sys_fail(0);
    }
#endif
    return io;
}

Очищает буфер вывода в ядре.

Для использования этого метода необходимо подключить модуль 'io/console'.

pathconf(p1) Показать исходный код
static VALUE
io_pathconf(VALUE io, VALUE arg)
{
    int name;
    long ret;
    rb_io_t *fptr;

    name = NUM2INT(arg);

    GetOpenFile(io, fptr);

    errno = 0;
    ret = fpathconf(fptr->fd, name);
    if (ret == -1) {
        if (errno == 0) /* no limit */
            return Qnil;
        rb_sys_fail("fpathconf");
    }
    return LONG2NUM(ret);
}

Возвращает переменную конфигурации имени файла, используя fpathconf().

name должна быть константой в Etc, которая начинается с PC_.

Возвращаемое значение — целое число или nil. nil означает неопределённый предел. (fpathconf() возвращает -1, но errno не устанавливается.)

require 'etc'
IO.pipe {|r, w|
  p w.pathconf(Etc::PC_PIPE_BUF) #=> 4096
}
pid → целое число Показать исходный код
static VALUE
rb_io_pid(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    if (!fptr->pid)
        return Qnil;
    return PIDT2NUM(fptr->pid);
}

Возвращает идентификатор процесса дочернего процесса, связанного с ios. Это будет установлено методом IO.popen.

pipe = IO.popen("-")
if pipe
  $stderr.puts "In parent, child pid is #{pipe.pid}"
else
  $stderr.puts "In child, pid is #{$$}"
end

возвращает:

In child, pid is 26209
In parent, child pid is 26209
pos → целое число Показать исходный код
static VALUE
rb_io_tell(VALUE io)
{
    rb_io_t *fptr;
    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);
}

Возвращает текущее смещение (в байтах) потока ios.

f = File.new("testfile")
f.pos    #=> 0
f.gets   #=> "This is line one\n"
f.pos    #=> 17
END_OF_DOCUMENT_MARKER
pos = integer → integer Показать исходный код
static VALUE
rb_io_set_pos(VALUE io, VALUE offset)
{
    rb_io_t *fptr;
    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);
}

Перемещает указатель на заданную позицию (в байтах) в ios. Гарантируется не точное попадание на заданную позицию, если ios в текстовом режиме.

f = File.new("testfile")
f.pos = 17
f.gets   #=> "This is line two\n"
pread(maxlen, offset[, outbuf]) → строка Показать исходный код
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;
    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;
}

Читает maxlen байт из ios с помощью системного вызова pread и возвращает их как строку без изменения смещения базового дескриптора. Это выгодно по сравнению с комбинированием IO#seek и IO#read, так как это атомарная операция, что позволяет нескольким потокам/процессам совместно использовать тот же объект IO для чтения файла в различных местах. Это обходит любые буферизации в пользовательском пространстве слоя IO. Если необязательный аргумент outbuf присутствует, он должен ссылаться на String, который получит данные. При ошибке генерирует SystemCallError, при достижении конца файла EOFError и NotImplementedError, если платформа не поддерживает системный вызов.

File.write("testfile", "This is line one\nThis is line two\n")
File.open("testfile") do |f|
  p f.read           # => "This is line one\nThis is line two\n"
  p f.pread(12, 0)   # => "This is line"
  p f.pread(9, 8)    # => "line one\n"
end
pressed?(p1) Показать исходный код
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;
}
print → nil Показать исходный код
print(obj, ...) → nil
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;
    }
    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;
}

Записывает заданный(ые) объект(ы) в ios. Возвращает nil.

Поток должен быть открыт для записи. Каждый объект, который не является строкой, будет преобразован с помощью вызова его метода to_s. При вызове без аргументов выводит содержимое $_.

Если разделитель полей вывода ($,) не nil, он вставляется между объектами. Если разделитель записей вывода ($\) не nil, он добавляется к выводу.

$stdout.print("This is ", 100, " percent.\n")

выводит:

This is 100 percent.
printf(format_string [, obj, ...]) → nil Показать исходный код
VALUE
rb_io_printf(int argc, const VALUE *argv, VALUE out)
{
    rb_io_write(out, rb_f_sprintf(argc, argv));
    return Qnil;
}

Форматирует и записывает в ios, преобразуя параметры под управлением строки форматирования. Смотрите Kernel#sprintf для деталей.

putc(obj) → obj Показать исходный код
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;
}

Если obj является Numeric, записывает символ, код которого равен наименее значащему байту obj. Если obj является String, записывает первый символ obj в ios. В противном случае, генерирует TypeError.

$stdout.putc "A"
$stdout.putc 65

выводит:

AA
puts(obj, ...) → nil Показать исходный код
VALUE
rb_io_puts(int argc, const VALUE *argv, VALUE out)
{
    int i, n;
    VALUE line, args[2];

    /* if no argument given, print newline. */
    if (argc == 0) {
        rb_io_write(out, rb_default_rs);
        return Qnil;
    }
    for (i=0; i<argc; i++) {
        if (RB_TYPE_P(argv[i], T_STRING)) {
            line = argv[i];
            goto string;
        }
        if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
            continue;
        }
        line = rb_obj_as_string(argv[i]);
      string:
        n = 0;
        args[n++] = line;
        if (RSTRING_LEN(line) == 0 ||
            !rb_str_end_with_asciichar(line, '\n')) {
            args[n++] = rb_default_rs;
        }
        rb_io_writev(out, n, args);
    }

    return Qnil;
}

Записывает заданный(ые) объект(ы) в ios. Записывает новую строку после любого, который не заканчивается последовательностью новой строки. Возвращает nil.

Поток должен быть открыт для записи. Если вызывается с аргументом массива, записывает каждый элемент на новой строке. Каждый объект, который не является строкой или массивом, будет преобразован с помощью вызова его метода to_s. Если вызывается без аргументов, выводит одиночную новую строку.

$stdout.puts("this", "is", ["a", "test"])

выводит:

this
is
a
test

Обратите внимание, что puts всегда использует новые строки и не зависит от разделителя записей вывода ($\).

pwrite(string, offset) → целое число Показать исходный код
static VALUE
rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
{
    rb_io_t *fptr;
    ssize_t n;
    struct prdwr_internal_arg arg;
    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_region(internal_pwrite_func, &arg, fptr->fd);
    if (n < 0) rb_sys_fail_path(fptr->pathv);
    rb_str_tmp_frozen_release(str, tmp);

    return SSIZET2NUM(n);
}

Записывает заданную строку в ios в offset с помощью системного вызова pwrite(). Это выгодно по сравнению с комбинированием IO#seek и IO#write, так как это атомарная операция, позволяющая нескольким потокам/процессам совместно использовать тот же объект IO для чтения файла в различных местах. Это обходит любые буферизации в пользовательском пространстве слоя IO. Возвращает количество записанных байт. При ошибке генерирует SystemCallError и NotImplementedError, если платформа не поддерживает системный вызов.

File.open("out", "w") do |f|
  f.pwrite("ABCDEF", 3)   #=> 6
end

File.read("out")          #=> "\u0000\u0000\u0000ABCDEF"
raw(min: nil, time: nil, intr: nil) {|io| } Показать исходный код
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);
}

Возвращает self в сыром режиме, и возвращает результат блока.

STDIN.raw(&:gets)

будет читать и возвращать строку без эха и редактирования строк.

Параметр min задаёт минимальное количество байт, которое должно быть получено при выполнении операции чтения. (по умолчанию: 1)

Параметр time задаёт таймаут в секундах с точностью до 1/10 секунды. (по умолчанию: 0)

Если параметр intr равен true, активирует специальные символы break, interrupt, quit и suspend.

Для получения дополнительной информации обратитесь к странице руководства termios.

Для использования этого метода необходимо подключить 'io/console'.

raw!(min: nil, time: nil, intr: nil) → io Показать исходный код
static VALUE
console_set_raw(int argc, VALUE *argv, VALUE io)
{
    conmode t;
    rb_io_t *fptr;
    int fd;
    rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);

    GetOpenFile(io, fptr);
    fd = GetReadFD(fptr);
    if (!getattr(fd, &t)) rb_sys_fail(0);
    set_rawmode(&t, optp);
    if (!setattr(fd, &t)) rb_sys_fail(0);
    return io;
}

Включает сырой режим и возвращает io.

Если режим терминала нужно вернуть обратно, используйте io.raw { ... }.

Смотрите IO#raw для получения подробной информации о параметрах.

Для использования этого метода необходимо подключить 'io/console'.

read([length [, outbuf]]) → строка, outbuf или nil Показать исходный код
static VALUE
io_read(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr;
    long n, len;
    VALUE length, str;
    int shrinkable;
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
    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 defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
    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 defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
    if (previous_mode == O_TEXT) {
        setmode(fptr->fd, O_TEXT);
    }
#endif
    if (n == 0) return Qnil;

    return str;
}

Читает length байт из потока ввода-вывода.

length должен быть неотрицательным целым числом или nil.

Если length положительное целое число, read пытается прочитать length байт без преобразования (двоичный режим). Возвращает nil , если EOF обнаружен до чтения чего-либо. Возвращается меньше чем length байт, если EOF обнаружен во время чтения. В случае целого значения length, результирующая строка всегда в кодировке ASCII-8BIT.

Если length опущено или равно nil, он читает до EOF и применяется преобразование кодировки, если применимо. Возвращается строка, даже если EOF обнаружен до чтения каких-либо данных.

Если length равно нулю, возвращается пустая строка ("").

Если необязательный аргумент outbuf присутствует, он должен ссылаться на String, который получит данные. outbuf будет содержать только полученные данные после вызова метода, даже если он не пуст в начале.

При вызове этого метода при достижении конца файла, он возвращает nil или "", в зависимости от length: read, read(nil), и read(0) возвращают "", read(positive_integer) возвращает nil.

f = File.new("testfile")
f.read(16)   #=> "This is line one"

# read whole file
open("file") do |f|
  data = f.read   # This returns a string even if the file is empty.
  # ...
end

# iterate over fixed length records
open("fixed-record-file") do |f|
  while record = f.read(256)
    # ...
  end
end

# iterate over variable length records,
# each record is prefixed by its 32-bit length
open("variable-record-file") do |f|
  while len = f.read(4)
    len = len.unpack("N")[0]   # 32-bit length
    record = f.read(len)       # This returns a string even if len is 0.
  end
end

Обратите внимание, что этот метод ведет себя как функция fread() в C. Это означает, что он пытается вызвать системные вызовы read(2) для чтения данных с заданной длиной (или до EOF). Это поведение сохраняется даже если ios в режиме без ожидания. (Этот метод нечувствителен к флагам блокировки, как и другие методы.) Если вам нужно поведение как одиночного системного вызова read(2), обратитесь к readpartial, read_nonblock и sysread.

read_nonblock(maxlen [, options]) → строка Показать исходный код
read_nonblock(maxlen, outbuf [, options]) → outbuf
# File io.rb, line 62
def read_nonblock(len, buf = nil, exception: true)
  __builtin_io_read_nonblock(len, buf, exception)
end

Считывает не более maxlen байт из ios с использованием системного вызова read(2) после установки O_NONBLOCK для базового дескриптора файла.

Если присутствует необязательный аргумент outbuf, он должен ссылаться на String, который получит данные. outbuf будет содержать только полученные данные после вызова метода, даже если он не был пустым изначально.

read_nonblock просто вызывает системный вызов read(2). Он вызывает все ошибки, которые вызывает системный вызов read(2): Errno::EWOULDBLOCK, Errno::EINTR и т. д. Вызывающая сторона должна обработать такие ошибки.

Если возникает исключение Errno::EWOULDBLOCK или Errno::EAGAIN, оно обрабатывается с помощью IO::WaitReadable. Таким образом, IO::WaitReadable может быть использован для перехвата исключений для повторной попытки read_nonblock.

read_nonblock вызывает EOFError при достижении конца файла.

На некоторых платформах, таких как Windows, режим без блокировки не поддерживается для объектов IO, кроме сокетов. В таких случаях будет поднято исключение Errno::EBADF.

Если буфер считанных байтов не пуст, read_nonblock читает из буфера как readpartial. В этом случае системный вызов read(2) не вызывается.

Когда read_nonblock генерирует исключение типа IO::WaitReadable, read_nonblock не должен вызываться, пока io не станет доступным для чтения, чтобы избежать зацикливания. Это можно сделать следующим образом.

# emulates blocking read (readpartial).
begin
  result = io.read_nonblock(maxlen)
rescue IO::WaitReadable
  IO.select([io])
  retry
end

Хотя IO#read_nonblock не генерирует IO::WaitWritable, OpenSSL::Buffering#read_nonblock может генерировать IO::WaitWritable. Если IO и SSL должны использоваться полиморфно, необходимо перехватить также IO::WaitWritable. Обратитесь к документации OpenSSL::Buffering#read_nonblock для примера кода.

Обратите внимание, что этот метод идентичен readpartial, за исключением того, что установлен флаг без блокировки.

Указав ключевой аргумент exception в false, можно указать, что read_nonblock не должен генерировать исключение IO::WaitReadable, а вместо этого возвращать символ :wait_readable. При достижении конца файла он вернёт nil вместо генерации исключения EOFError.

readbyte → целое число Показать исходный код
static VALUE
rb_io_readbyte(VALUE io)
{
    VALUE c = rb_io_getbyte(io);

    if (NIL_P(c)) {
        rb_eof_error();
    }
    return c;
}

Считывает байт так же, как с помощью IO#getbyte, но при достижении конца файла генерирует исключение EOFError.

readchar → строка Показать исходный код
static VALUE
rb_io_readchar(VALUE io)
{
    VALUE c = rb_io_getc(io);

    if (NIL_P(c)) {
        rb_eof_error();
    }
    return c;
}

Считывает строку длиной в один символ из ios. При достижении конца файла генерирует исключение EOFError.

f = File.new("testfile")
f.readchar   #=> "h"
f.readchar   #=> "e"
readline(sep=$/ [, getline_args]) → строка Показать исходный код
readline(limit [, getline_args]) → строка
readline(sep, limit [, getline_args]) → строка
static VALUE
rb_io_readline(int argc, VALUE *argv, VALUE io)
{
    VALUE line = rb_io_gets_m(argc, argv, io);

    if (NIL_P(line)) {
        rb_eof_error();
    }
    return line;
}

Считывает строку, как с помощью IO#gets, но при достижении конца файла генерирует исключение EOFError.

readlines(sep=$/ [, getline_args]) → массив Показать исходный код
readlines(limit [, getline_args]) → массив
readlines(sep, limit [, getline_args]) → массив
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);
}

Считывает все строки из ios и возвращает их в массиве. Строки разделяются необязательным sep. Если sep равно nil, вся оставшаяся часть потока возвращается как один элемент. Если первый аргумент — целое число или задан необязательный второй аргумент, возвращаемая строка не будет длиннее заданного значения в байтах. Поток должен быть открыт для чтения, иначе будет поднято исключение IOError.

f = File.new("testfile")
f.readlines[0]   #=> "This is line one\n"

f = File.new("testfile", chomp: true)
f.readlines[0]   #=> "This is line one"

См. IO.readlines для получения дополнительной информации о getline_args.

readpartial(maxlen) → строка Показать исходный код
readpartial(maxlen, outbuf) → outbuf
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;
}

Считывает не более maxlen байт из потока ввода-вывода. Он блокируется только если у ios нет данных, доступных немедленно. Он не блокируется, если какие-то данные доступны.

Если необязательный аргумент outbuf присутствует, он должен ссылаться на String, который получит данные. outbuf будет содержать только полученные данные после вызова метода, даже если он не был пустым изначально.

При достижении конца файла генерируется исключение EOFError.

readpartial разработан для потоков, таких как pipe, socket, tty и т. д. Он блокируется только когда нет данных, немедленно доступных. Это означает, что он блокируется только когда выполняются все следующие условия.

  • Буфер байтов в объекте IO пуст.

  • Содержание потока пусто.

  • Поток не достиг конца файла.

Когда readpartial блокируется, он ожидает данных или конца файла в потоке. Если достигаются данные, readpartial возвращает их. Если достигается конец файла, readpartial генерирует исключение EOFError.

Когда readpartial не блокируется, он возвращает или генерирует исключение немедленно. Если буфер байтов не пуст, он возвращает данные из буфера. В противном случае, если поток содержит данные, он возвращает их. В противном случае, если поток достиг конца файла, он генерирует исключение EOFError.

r, w = IO.pipe           #               buffer          pipe content
w << "abc"               #               ""              "abc".
r.readpartial(4096)      #=> "abc"       ""              ""
r.readpartial(4096)      # blocks because buffer and pipe is empty.

r, w = IO.pipe           #               buffer          pipe content
w << "abc"               #               ""              "abc"
w.close                  #               ""              "abc" EOF
r.readpartial(4096)      #=> "abc"       ""              EOF
r.readpartial(4096)      # raises EOFError

r, w = IO.pipe           #               buffer          pipe content
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"     ""              ""

Обратите внимание, что readpartial ведет себя подобно sysread. Различия заключаются в следующем:

  • Если буфер байтов не пуст, данные считываются из буфера вместо «sysread для буферизованного IO (IOError)».

  • Он не вызывает Errno::EWOULDBLOCK и Errno::EINTR. При столкновении readpartial с EWOULDBLOCK и EINTR системным вызовом, readpartial повторяет системный вызов.

Последнее означает, что readpartial нечувствителен к флагу без блокировки. Он блокируется в ситуации, когда IO#sysread вызывает Errno::EWOULDBLOCK, как если бы fd находился в режиме блокировки.

ready? → true или false Показать исходный код
static VALUE
io_ready_p(VALUE io)
{
    rb_io_t *fptr;
    struct timeval tv = {0, 0};

    GetOpenFile(io, fptr);
    rb_io_check_readable(fptr);
    if (rb_io_read_pending(fptr)) return Qtrue;
    if (wait_for_single_fd(fptr, RB_WAITFD_IN, &tv))
        return Qtrue;
    return Qfalse;
}

Возвращает true, если данные доступны для чтения без блокировки, или false.

reopen(other_IO) → ios Показать исходный код
reopen(path, mode [, opt]) → ios
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;
        convconfig_t convconfig;

        rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
        if (IS_PREP_STDIO(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(0);
    }
    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;
}

Переустанавливает ассоциацию ios с потоком ввода-вывода, заданным в other_IO, или с новым потоком, открытым по пути path. Это может динамически изменить фактический класс этого потока. Параметры mode и opt принимают те же значения, что и IO.open.

f1 = File.new("testfile")
f2 = File.new("testfile")
f2.readlines[0]   #=> "This is line one\n"
f2.reopen(f1)     #=> #<File:testfile>
f2.readlines[0]   #=> "This is line one\n"
rewind → 0 Показать исходный код
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);
}

Перемещает ios к началу входных данных, сбрасывая lineno до нуля.

f = File.new("testfile")
f.readline   #=> "This is line one\n"
f.rewind     #=> 0
f.lineno     #=> 0
f.readline   #=> "This is line one\n"

Обратите внимание, что его нельзя использовать с потоками, такими как pipes, ttys и сокеты.

scroll_backward(p1) Показать исходный код
static VALUE
console_scroll_backward(VALUE io, VALUE val)
{
    return console_scroll(io, -NUM2INT(val));
}
scroll_forward(p1) Показать исходный код
static VALUE
console_scroll_forward(VALUE io, VALUE val)
{
    return console_scroll(io, +NUM2INT(val));
}
seek(amount, whence=IO::SEEK_SET) → 0 Показать исходный код
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);
}

Перемещает указатель потока на заданное смещение anInteger в соответствии со значением whence:

:CUR or IO::SEEK_CUR  | Seeks to _amount_ plus current position
----------------------+--------------------------------------------------
:END or IO::SEEK_END  | Seeks to _amount_ plus end of stream (you
                      | probably want a negative value for _amount_)
----------------------+--------------------------------------------------
:SET or IO::SEEK_SET  | Seeks to the absolute location given by _amount_

Пример:

f = File.new("testfile")
f.seek(-13, IO::SEEK_END)   #=> 0
f.readline                  #=> "And so on...\n"
set_encoding(ext_enc) → io Показать исходный код
set_encoding("ext_enc:int_enc") → io
set_encoding(ext_enc, int_enc) → io
set_encoding("ext_enc:int_enc", opt) → io
set_encoding(ext_enc, int_enc, opt) → io
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 rb_funcallv(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;
}

Если указан единственный аргумент, строка, считываемая из io, помечается указанным кодированием. Если кодирование задано как разделенные двоеточием два имени кодировок "A:B", считываемая строка преобразуется из кодировки A (внешнее кодирование) в кодировку B (внутреннее кодирование), а затем помечается кодировкой B. Если указаны два аргумента, они должны быть объектами кодировки или именами кодировок, причём первый — внешнее кодирование, а второй — внутреннее. Если указаны внешнее и внутреннее кодирование, необязательный аргумент хеш задаёт параметры преобразования.

set_encoding_by_bom → encoding or nil Показать исходный код
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);
}

Проверяет, начинается ли ios с BOM, и затем потребляет его и устанавливает внешнее кодирование. Возвращает результат кодирования, если найдено, или nil. Если ios не в режиме binmode или его кодирование уже установлено, будет возбуждено исключение.

File.write("bom.txt", "\u{FEFF}abc")
ios = File.open("bom.txt", "rb")
ios.set_encoding_by_bom    #=>  #<Encoding:UTF-8>

File.write("nobom.txt", "abc")
ios = File.open("nobom.txt", "rb")
ios.set_encoding_by_bom    #=>  nil
stat → stat Показать исходный код
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);
}

Возвращает информацию о статусе ios как объект типа 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
sync → true or false Показать исходный код
static VALUE
rb_io_sync(VALUE io)
{
    rb_io_t *fptr;

    io = GetWriteIO(io);
    GetOpenFile(io, fptr);
    return (fptr->mode & FMODE_SYNC) ? Qtrue : Qfalse;
}

Возвращает текущий режим «синхронизации» ios. Когда режим синхронизации true, весь вывод немедленно записывается в основную операционную систему и не буферизуется Ruby. См. также IO#fsync.

f = File.new("testfile")
f.sync   #=> false
sync = boolean → boolean Показать исходный код
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;
}

Устанавливает режим «синхронизации» в true или false. Когда режим синхронизации true, весь вывод немедленно записывается в основную операционную систему и не буферизуется внутри. Возвращает новое состояние. См. также IO#fsync.

f = File.new("testfile")
f.sync = true
sysread(maxlen[, outbuf]) → string Показать исходный код
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");
    }

    /*
     * FIXME: removing rb_thread_wait_fd() here changes sysread semantics
     * on non-blocking IOs.  However, it's still currently possible
     * for sysread to raise Errno::EAGAIN if another thread read()s
     * the IO after we return from rb_thread_wait_fd() but before
     * we call read()
     */
    rb_thread_wait_fd(fptr->fd);

    rb_io_check_closed(fptr);

    io_setstrbuf(&str, ilen);
    iis.fd = fptr->fd;
    iis.nonblock = 1; /* for historical reasons, maybe (see above) */
    iis.buf = RSTRING_PTR(str);
    iis.capa = ilen;
    n = read_internal_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;
}

Читает maxlen байтов из ios с помощью низкоуровневого чтения и возвращает их как строку. Не смешивайте с другими методами, которые читают из ios, иначе результаты могут быть непредсказуемыми.

Если необязательный аргумент outbuf присутствует, он должен ссылаться на String, который получит данные. outbuf будет содержать только полученные данные после вызова метода, даже если он не пустой в начале.

Возбуждает SystemCallError при ошибке и EOFError в конце файла.

f = File.new("testfile")
f.sysread(16)   #=> "This is line one"
sysseek(offset, whence=IO::SEEK_SET) → integer Показать исходный код
static VALUE
rb_io_sysseek(int argc, VALUE *argv, VALUE io)
{
    VALUE offset, ptrname;
    int whence = SEEK_SET;
    rb_io_t *fptr;
    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);
}

Перемещает указатель на заданное смещение offset в потоке в соответствии со значением whence (см. IO#seek для значений whence). Возвращает новое смещение в файле.

f = File.new("testfile")
f.sysseek(-13, IO::SEEK_END)   #=> 53
f.sysread(10)                  #=> "And so on."
syswrite(string) → integer Показать исходный код
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_write_internal(fptr->fd, ptr, len);
    if (n < 0) rb_sys_fail_path(fptr->pathv);
    rb_str_tmp_frozen_release(str, tmp);

    return LONG2FIX(n);
}

Записывает заданную строку в ios с помощью низкоуровневой записи. Возвращает количество записанных байтов. Не смешивайте с другими методами, которые записывают в ios, иначе результаты могут быть непредсказуемыми. Возбуждает SystemCallError при ошибке.

f = File.new("out", "w")
f.syswrite("ABCDEF")   #=> 6
tell → integer Показать исходный код
static VALUE
rb_io_tell(VALUE io)
{
    rb_io_t *fptr;
    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);
}

Возвращает текущее смещение (в байтах) ios.

f = File.new("testfile")
f.pos    #=> 0
f.gets   #=> "This is line one\n"
f.pos    #=> 17
to_i()
Псевдоним для: fileno
to_io → ios Показать исходный код
static VALUE
rb_io_to_io(VALUE io)
{
    return io;
}

Возвращает ios.

tty? → true or false Показать исходный код
static VALUE
rb_io_isatty(VALUE io)
{
    rb_io_t *fptr;

    GetOpenFile(io, fptr);
    if (isatty(fptr->fd) == 0)
        return Qfalse;
    return Qtrue;
}

Возвращает true если ios ассоциирован с устройством терминала (tty), false в противном случае.

File.new("testfile").isatty   #=> false
File.new("/dev/tty").isatty   #=> true
ungetbyte(string) → nil Показать исходный код
ungetbyte(integer) → nil
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;
}

Возвращает байты (переданные в качестве параметра) в ios, таким образом, последующее буферизованное чтение вернёт его. Только один байт может быть возвращён обратно перед последующей операцией чтения (то есть, вы сможете прочитать только последний из нескольких байтов, которые были возвращены обратно). Не имеет эффекта при чтении без буферизации (таких как IO#sysread).

f = File.new("testfile")   #=> #<File:testfile>
b = f.getbyte              #=> 0x38
f.ungetbyte(b)             #=> nil
f.getbyte                  #=> 0x38
ungetc(string) → nil Показать исходный код
VALUE
rb_io_ungetc(VALUE io, VALUE c)
{
    rb_io_t *fptr;
    long len;

    GetOpenFile(io, fptr);
    rb_io_check_char_readable(fptr);
    if (NIL_P(c)) return Qnil;
    if (FIXNUM_P(c)) {
        c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
    }
    else if (RB_TYPE_P(c, T_BIGNUM)) {
        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;
}

Возвращает один символ (переданный в качестве параметра) в ios, таким образом, последующее буферизованное чтение символа вернёт его. Только один символ может быть возвращён обратно перед последующей операцией чтения (то есть, вы сможете прочитать только последний из нескольких символов, которые были возвращены обратно). Не имеет эффекта при чтении без буферизации (таких как IO#sysread).

f = File.new("testfile")   #=> #<File:testfile>
c = f.getc                 #=> "8"
f.ungetc(c)                #=> nil
f.getc                     #=> "8"
wait(timeout = nil, mode = :read) → IO, true or nil Показать исходный код
static VALUE
io_wait_readwrite(int argc, VALUE *argv, VALUE io)
{
    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);
    if (!event) event = RB_WAITFD_IN;
    if ((event & RB_WAITFD_IN) && rb_io_read_pending(fptr))
        return Qtrue;
    if (wait_for_single_fd(fptr, event, tv))
        return io;
    return Qnil;
}

Ожидает, пока IO не станет доступным для чтения или записи без блокирования и возвращает self, или nil при истечении времени ожидания. Возвращает true немедленно, когда доступны буферизованные данные. Необязательный параметр mode может быть :read, :write, или :read_write.

wait_readable → IO, true or nil Показать исходный код
wait_readable(timeout) → IO, true or nil
static VALUE
io_wait_readable(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr;
    struct timeval timerec;
    struct timeval *tv;

    GetOpenFile(io, fptr);
    rb_io_check_readable(fptr);
    tv = get_timeout(argc, argv, &timerec);
    if (rb_io_read_pending(fptr)) return Qtrue;
    if (wait_for_single_fd(fptr, RB_WAITFD_IN, tv)) {
        return io;
    }
    return Qnil;
}

Ожидает, пока IO не станет доступным для чтения без блокирования и возвращает self, или nil при истечении времени ожидания. Возвращает true немедленно, когда доступны буферизованные данные.

wait_writable → IO Показать исходный код
wait_writable(timeout) → IO or nil
static VALUE
io_wait_writable(int argc, VALUE *argv, VALUE io)
{
    rb_io_t *fptr;
    struct timeval timerec;
    struct timeval *tv;

    GetOpenFile(io, fptr);
    rb_io_check_writable(fptr);
    tv = get_timeout(argc, argv, &timerec);
    if (wait_for_single_fd(fptr, RB_WAITFD_OUT, tv)) {
        return io;
    }
    return Qnil;
}

Ожидает, пока IO не станет доступным для записи без блокирования и возвращает self или nil при истечении времени ожидания.

winsize → [rows, columns] Показать исходный код
static VALUE
console_winsize(VALUE io)
{
    rb_io_t *fptr;
    int fd;
    rb_console_size_t ws;

    GetOpenFile(io, fptr);
    fd = GetWriteFD(fptr);
    if (!getwinsize(fd, &ws)) rb_sys_fail(0);
    return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
}

Возвращает размер консоли.

Для использования этого метода необходимо выполнить require 'io/console'.

winsize = [rows, columns] Показать исходный код
static VALUE
console_set_winsize(VALUE io, VALUE size)
{
    rb_io_t *fptr;
    rb_console_size_t ws;
#if defined _WIN32
    HANDLE wh;
    int newrow, newcol;
    BOOL ret;
#endif
    VALUE row, col, xpixel, ypixel;
    const VALUE *sz;
    int fd;
    long sizelen;

    GetOpenFile(io, fptr);
    size = rb_Array(size);
    if ((sizelen = RARRAY_LEN(size)) != 2 && sizelen != 4) {
        rb_raise(rb_eArgError,
                 "wrong number of arguments (given %ld, expected 2 or 4)",
                 sizelen);
    }
    sz = RARRAY_CONST_PTR(size);
    row = sz[0], col = sz[1], xpixel = ypixel = Qnil;
    if (sizelen == 4) xpixel = sz[2], ypixel = sz[3];
    fd = GetWriteFD(fptr);
#if defined TIOCSWINSZ
    ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0;
#define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
    SET(row);
    SET(col);
    SET(xpixel);
    SET(ypixel);
#undef SET
    if (!setwinsize(fd, &ws)) rb_sys_fail(0);
#elif defined _WIN32
    wh = (HANDLE)rb_w32_get_osfhandle(fd);
#define SET(m) new##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
    SET(row);
    SET(col);
#undef SET
    if (!NIL_P(xpixel)) (void)NUM2UINT(xpixel);
    if (!NIL_P(ypixel)) (void)NUM2UINT(ypixel);
    if (!GetConsoleScreenBufferInfo(wh, &ws)) {
        rb_syserr_fail(LAST_ERROR, "GetConsoleScreenBufferInfo");
    }
    ws.dwSize.X = newcol;
    ret = SetConsoleScreenBufferSize(wh, ws.dwSize);
    ws.srWindow.Left = 0;
    ws.srWindow.Top = 0;
    ws.srWindow.Right = newcol-1;
    ws.srWindow.Bottom = newrow-1;
    if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
        rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
    }
    /* retry when shrinking buffer after shrunk window */
    if (!ret && !SetConsoleScreenBufferSize(wh, ws.dwSize)) {
        rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo");
    }
    /* remove scrollbar if possible */
    if (!SetConsoleWindowInfo(wh, TRUE, &ws.srWindow)) {
        rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo");
    }
#endif
    return io;
}

Пытается установить размер консоли. Эффект зависит от платформы и среды выполнения.

Для использования этого метода необходимо выполнить require 'io/console'.

write(string, ...) → integer Показать исходный код
static VALUE
io_write_m(int argc, VALUE *argv, VALUE io)
{
    if (argc != 1) {
        return io_writev(argc, argv, io);
    }
    else {
        VALUE str = argv[0];
        return io_write(io, str, 0);
    }
}

Записывает указанные строки в ios. Поток должен быть открыт для записи. Аргументы, которые не являются строками, будут преобразованы в строку с использованием to_s. Возвращает общее количество записанных байтов.

count = $stdout.write("This is", " a test\n")
puts "That was #{count} bytes of data"

выводит:

This is a test
That was 15 bytes of data
write_nonblock(string) → integer
write_nonblock(string [, options]) → integer
# File io.rb, line 120
def write_nonblock(buf, exception: true)
  __builtin_io_write_nonblock(buf, exception)
end

Записывает заданную строку в ios, используя системный вызов write(2) после установки O_NONBLOCK для базового дескриптора файла.

Возвращает количество записанных байтов.

write_nonblock просто вызывает системный вызов write(2). Это вызывает все ошибки, которые вызывает системный вызов write(2): Errno::EWOULDBLOCK, Errno::EINTR и т. д. Результат также может быть меньше, чем string.length (частичная запись). Вызывающий должен обращать внимание на такие ошибки и частичную запись.

Если возникает исключение Errno::EWOULDBLOCK или Errno::EAGAIN, оно дополняется IO::WaitWritable. Поэтому IO::WaitWritable можно использовать для перехвата исключений для повторной попытки write_nonblock.

# Creates a pipe.
r, w = IO.pipe

# write_nonblock writes only 65536 bytes and return 65536.
# (The pipe size is 65536 bytes on this environment.)
s = "a" * 100000
p w.write_nonblock(s)     #=> 65536

# write_nonblock cannot write a byte and raise EWOULDBLOCK (EAGAIN).
p w.write_nonblock("b")   # Resource temporarily unavailable (Errno::EAGAIN)

Если буфер записи не пустой, он сначала очищается.

Когда write_nonblock вызывает исключение типа IO::WaitWritable, write_nonblock не следует вызывать до тех пор, пока io не станет доступным для записи, чтобы избежать бесконечного цикла. Это можно сделать следующим образом.

begin
  result = io.write_nonblock(string)
rescue IO::WaitWritable, Errno::EINTR
  IO.select(nil, [io])
  retry
end

Обратите внимание, что это не гарантирует запись всех данных в строке. Длина записанных данных сообщается как результат, и ее следует проверять позже.

На некоторых платформах, таких как Windows, write_nonblock не поддерживается в зависимости от типа объекта IO. В таких случаях write_nonblock вызывает Errno::EBADF.

Указав ключевой аргумент exception в false, вы можете указать, что write_nonblock не должен вызывать исключение IO::WaitWritable, а вместо этого возвращает символ :wait_writable.

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API