IO
class IO
Parent:ObjectIncluded modules:File::Constants, Enumerable
期望库加入IO实例方法,对tcl的期望扩展做类似的操作。
为了使用这种方法,你必须要求:
require 'expect'
请看使用期望。
IO类是Ruby中所有输入和输出的基础。I/O流可能是双工的
(即双向的),因此可能会使用多个本地操作系统流。
本节中的许多示例都使用File类,这是IO的唯一标准子类。这两个班级密切相关。像File类一样,来自IO的Socket库子类(如TCPSocket或UDPSocket)。
Kernel#open方法可以为这些类型的参数创建一个IO(或File)对象:
- 一个普通的字符串表示一个适合底层操作系统的文件名。
- 一个以字符开始的字符串
"|"
表示一个子进程。跟在该字符串后面的字符串的其余部分"|"
被调用为具有连接到它的相应输入/输出通道的进程。
- 等于的字符串
"|-"
将创建另一个Ruby实例作为子进程.IO可以用不同的文件模式(只读,只写)和适当的转换编码打开。
- ::console
- #raw
- #raw!
- #cooked
- #cooked!
- #getch
- #echo=
- #echo?
- #noecho
- #winsize
- #winsize=
- #iflush
- #ioflush
- #oflush
- 新行转换已禁用
- 编码转换禁用
- 内容被视为ASCII-8BIT
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;
}
binmode? → true or false
如果ios
是binmode,则返回true
。
static VALUE
rb_io_binmode_p(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr
return fptr->mode & FMODE_BINMODE ? Qtrue : Qfalse;
}
bytes()
这是一个不推荐的别名each_byte
。
static VALUE
rb_io_bytes(VALUE io)
{
rb_warn("IO#bytes is deprecated; use #each_byte instead"
if (!rb_block_given_p())
return rb_enumeratorize(io, ID2SYM(rb_intern("each_byte")), 0, 0
return rb_io_each_byte(io
}
chars()
这是一个不推荐的别名each_char
。
static VALUE
rb_io_chars(VALUE io)
{
rb_warn("IO#chars is deprecated; use #each_char instead"
if (!rb_block_given_p())
return rb_enumeratorize(io, ID2SYM(rb_intern("each_char")), 0, 0
return rb_io_each_char(io
}
close → nil
关闭ios
并刷新任何挂起的写入操作系统。该流不可用于任何进一步的数据操作; 一IOError
,如果这样的尝试升高。I/O流在被垃圾回收器声明时会自动关闭。
如果ios
被打开IO.popen
,close
设置$?
。
从Ruby 2.3开始,在封闭的IO对象上调用这个方法就被忽略了。
static VALUE
rb_io_close_m(VALUE io)
{
rb_io_t *fptr = rb_io_get_fptr(io
if (fptr->fd < 0) {
return Qnil;
}
rb_io_close(io
return Qnil;
}
close_on_exec = bool → true or false
设置一个关闭执行标志。
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 2.0.0开始,Ruby默认设置所有文件描述符的close-on-exec标志。所以你不需要自己设定。另外,如果另一个线程使用fork()和exec()(例如通过system()方法),则取消设置close-on-exec标志可能导致文件描述符泄漏。如果您真的需要将文件描述符继承到子进程,请使用spawn()的参数,如fd => fd。
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 == -1) 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 == -1) rb_sys_fail_path(fptr->pathv
}
}
return Qnil;
}
close_on_exec? → true or false
如果ios
将在exec上关闭,则返回true
。
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
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;
}
close_read → nil Show source
关闭duplex I/O流的读取端(即,包含读取和写入流的管道,例如管道)。IOError
如果数据流不是双工的,会引发一次。
f = IO.popen("/bin/sh","r+")
f.close_read
f.readlines
produces:
prog.rb:3:in `readlines': not opened for reading (IOError)
from prog.rb:3
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
}
close_write → nil Show source
关闭duplex I/O流的写入结束(即,包含读取和写入流的管道,例如管道)。IOError
如果数据流不是双工的,会引发一次。
f = IO.popen("/bin/sh","r+")
f.close_write
f.print "nowhere"
produces:
prog.rb:3:in `write': not opened for writing (IOError)
from prog.rb:3:in `print'
from prog.rb:3
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;
}
closed? → true or false Show source
如果ios
完全关闭(对于双向流,读写器),则返回true
,否则返回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
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;
}
codepoints()
这是一个不推荐的别名each_codepoint
。
static VALUE
rb_io_codepoints(VALUE io)
{
rb_warn("IO#codepoints is deprecated; use #each_codepoint instead"
if (!rb_block_given_p())
return rb_enumeratorize(io, ID2SYM(rb_intern("each_codepoint")), 0, 0
return rb_io_each_codepoint(io
}
cooked {|io| }
self
cooked模式下的产量。
STDIN.cooked(&:gets)
将读取并返回一行回显和行编辑。
您必须要求'io/console'才能使用此方法。
static VALUE
console_cooked(VALUE io)
{
return ttymode(io, rb_yield, set_cookedmode, NULL
}
cooked!
启用cooked模式。
如果终端模式需要返回,请使用io.cooked {...}。
您必须要求'io/console'才能使用此方法。
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;
}
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.X), UINT2NUM(ws.dwCursorPosition.Y)
}
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)
}
each(sep=$/) {|line| block } → ios
each(limit) {|line| block } → ios
each(sep,limit) {|line| block } → ios
each(...) → an_enumerator
each_line(sep=$/) {|line| block } → ios
each_line(limit) {|line| block } → ios
each_line(sep,limit) {|line| block } → ios
each_line(...) → an_enumerator
为ios中的
每一行执行块,其中行由sep
分隔。ios
必须打开以供阅读或IOError
将会被提出。
如果没有给出块,则返回一个枚举器。
f = File.new("testfile")
f.each {|line| puts "#{f.lineno}: #{line}" }
produces:
1: This is line one
2: This is line two
3: This is line three
4: And so on...
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;
}
each_byte {|byte| block } → ios Show source
each_byte → an_enumerator
为ios中的
每个字节(0..255)调用给定的块一次,将该字节作为参数传递。该流必须打开阅读或IOError
将被提出。
如果没有给出块,则返回一个枚举器。
f = File.new("testfile")
checksum = 0
f.each_byte {|x| checksum ^= x } #=> #<File:testfile>
checksum #=> 12
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;
}
each_char {|c| block } → ios Show source
each_char → an_enumerator
为ios中的
每个字符调用一次给定的块,将该字符作为参数传递。该流必须打开阅读或IOError
将被提出。
如果没有给出块,则返回一个枚举器。
f = File.new("testfile")
f.each_char {|c| print c, ' ' } #=> #<File:testfile>
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;
}
each_codepoint {|c| block } → ios Show source
codepoints {|c| block } → ios
each_codepoint → an_enumerator
codepoints → an_enumerator
传递ios
Integer
中每个字符的序号,将代码点作为参数传递。该流必须打开阅读或将被提出。IOError
如果没有给出块,则返回一个枚举器。
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;
}
each_line(sep=$/) {|line| block } → ios
each_line(limit) {|line| block } → ios
each_line(sep,limit) {|line| block } → ios
each_line(...) → an_enumerator
为ios中的
每一行执行块,其中行由sep
分隔。ios
必须打开以供阅读或IOError
将会被提出。
如果没有给出块,则返回一个枚举器。
f = File.new("testfile")
f.each {|line| puts "#{f.lineno}: #{line}" }
produces:
1: This is line one
2: This is line two
3: This is line three
4: And so on...
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;
}
echo = flag Show source
启用/禁用回显。在某些平台上,此标志和原始/熟化模式的所有组合可能无效。
您必须要求'io / console'才能使用此方法。
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;
}
echo? → true or false Show source
如果启用了回显,则返回true
。
您必须要求'io/console'才能使用此方法。
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;
}
eof → true or false
eof? → true or false
如果ios
在文件末尾,表示没有更多数据要读取,则返回true 。该流必须打开阅读或IOError
将被提出。
f = File.new("testfile")
dummy = f.readlines
f.eof #=> true
如果ios
是诸如管道或套接字之类的流,则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
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;
}
eof? → true or false
如果ios
在文件末尾,表示没有更多数据要读取,则返回true 。该流必须打开阅读或IOError
将被提出。
f = File.new("testfile")
dummy = f.readlines
f.eof #=> true
如果ios
是诸如管道或套接字之类的流,则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#rewind
(不适用于某些流),否则IO#sysread
可能无法按照您IO#eof?
的意愿行事。
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;
}
IO#expect(pattern,timeout=9999999) → Array
IO#expect(pattern,timeout=9999999) { |result| ... } → nil
从IO中读取,直到给定的pattern
匹配或timeout
结束。
它返回一个带有读缓冲区的数组,然后是匹配。如果给出了一个块,结果将被输出到该块并返回nil。
在没有块的情况下调用时,它会一直等待,直到pattern
从IO获得匹配给定的输入或者超时过后指定的时间。从IO获取模式时返回数组。数组的第一个元素是从IO中获得的整个字符串,直到模式匹配,然后是指示哪些模式与正则表达式中的锚点匹配的元素。
可选的超时参数以秒为单位定义等待模式的总时间。如果超时到期或找到eof,返回或放弃nil。但是,超时会话中的缓冲区将保留用于下一个期望调用。默认超时时间为9999999秒。
# File ext/pty/lib/expect.rb, line 32
def expect(pat,timeout=9999999)
buf = ''
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).chr
elsif !IO.select([self],nil,nil,timeout) or eof? then
result = nil
@unusedBuf = buf
break
else
c = getc.chr
end
buf << c
if $expect_verbose
STDOUT.print c
STDOUT.flush
end
if mat=e_pat.match(buf) then
result = [buf,*mat.to_a[1..-1]]
break
end
end
if block_given? then
yield result
else
return result
end
nil
end
external_encoding → encoding
返回表示文件编码的Encoding对象。如果io是写入模式并且没有指定编码,则返回nil
。
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)
}
fcntl(integer_cmd, arg) → integer Show source
提供一种发布低级命令来控制或查询面向文件的I/O流的机制。参数和结果依赖于平台。如果arg
是数字,则其值直接传递。如果它是一个字符串,则将其解释为二进制字节序列(Array#pack
可能是构建此字符串的一种有用方法)。在Unix平台上,查看fcntl(2)
详情。没有在所有平台上实施。
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
}
fdatasync → 0 or nil
在立即写入所有缓冲数据的ios
到磁盘。
如果底层操作系统不支持fdatasync(2)
,IO#fsync
则会调用(可能会引发NotImplementedError
)。
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
}
fileno → integer
to_i → integer
返回表示ios
的数字文件描述符的整数。
$stdin.fileno #=> 0
$stdout.fileno #=> 1
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
}
另外别名为:to_i
flush → ios
将ios
中的任何缓冲数据刷新到底层操作系统(请注意,这仅仅是Ruby内部缓冲;操作系统也可以缓冲数据)。
$stdout.print "no newline"
$stdout.flush
produces:
no newline
VALUE
rb_io_flush(VALUE io)
{
return rb_io_flush_raw(io, 1
}
fsync → 0 or nil
在立即写入所有缓冲数据的ios
到磁盘。请注意,fsync
与使用不同IO#sync=
。后者确保数据从Ruby的缓冲区刷新,但不保证底层操作系统实际将其写入磁盘。
NotImplementedError
如果底层操作系统不支持fsync(2),
则会引发此问题。
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
}
getbyte → integer or nil
从ios
获取下一个8位字节(0..255)。nil
如果在文件结尾处调用则返回。
f = File.new("testfile")
f.getbyte #=> 84
f.getbyte #=> 104
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
}
getc → string or nil
从ios
读取一个字符的字符串。nil
如果在文件结尾处调用则返回。
f = File.new("testfile")
f.getc #=> "h"
f.getc #=> "e"
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
}
getch(min: nil, time: nil) → char
读取并返回原始模式下的字符。
您必须要求'io/console'才能使用此方法。
static VALUE
console_getch(int argc, VALUE *argv, VALUE io)
{
rawmode_arg_t opts, *optp = rawmode_opt(argc, argv, &opts
return ttymode(io, getc_call, set_rawmode, optp
}
getpass(prompt=nil) → string
读取并返回没有回显的行。prompt
除非是,否则打印nil
。
您必须要求'io/console'才能使用此方法。
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
}
gets(sep=$/) → string or nil
gets(limit) → string or nil
gets(sep, limit) → string or nil
从I / O流中读取下一个“line”; 行由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"
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;
}
goto(p1, p2)
static VALUE
console_goto(VALUE io, VALUE x, VALUE y)
{
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;
}
iflush
在内核中刷新输入缓冲区。
您必须要求'io/console'才能使用此方法。
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;
}
inspect → string
返回描述此IO对象的字符串。
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, ">"
}
internal_encoding → 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)
}
ioctl(integer_cmd, arg) → integer
提供一种发布低级命令来控制或查询I/O设备的机制。参数和结果依赖于平台。如果arg
是数字,则其值直接传递。如果它是一个字符串,它将被解释为一个二进制字节序列。在Unix平台上,查看ioctl(2)
详情。没有在所有平台上实施。
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
}
ioflush
刷新内核中的输入和输出缓冲区。
您必须要求'io/console'才能使用此方法。
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;
}
isatty → true or false
如果ios
与终端设备(tty)关联则返回,false
否则返回true
。
File.new("testfile").isatty #=> false
File.new("/dev/tty").isatty #=> true
static VALUE
rb_io_isatty(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr
if (isatty(fptr->fd) == 0)
return Qfalse;
return Qtrue;
}
lineno → integer
返回ios
中的当前行号。该流必须打开才能阅读。lineno
统计被调用的次数,而不是所遇到的换行符的数量。如果使用换行符以外的分隔符调用get,则这两个值将有所不同。
像每个$/
,行和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
static VALUE
rb_io_lineno(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr
rb_io_check_char_readable(fptr
return INT2NUM(fptr->lineno
}
lineno = integer → integer
手动将当前行号设置为给定值。$.
仅在下次阅读时更新。
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
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;
}
lines(*args)
这是一个不推荐的别名each_line
。
static VALUE
rb_io_lines(int argc, VALUE *argv, VALUE io)
{
rb_warn("IO#lines is deprecated; use #each_line instead"
if (!rb_block_given_p())
return rb_enumeratorize(io, ID2SYM(rb_intern("each_line")), argc, argv
return rb_io_each_line(argc, argv, io
}
noecho {|io| }
产量self
与禁用回声返回。
STDIN.noecho(&:gets)
将读取并返回一个没有回显的行。
您必须要求'io/console'才能使用此方法。
static VALUE
console_noecho(VALUE io)
{
return ttymode(io, rb_yield, set_noecho, NULL
}
nonblock {|io| } → io
nonblock(boolean) {|io| } → io
self
非阻塞模式产量。
当false
作为参数给出时,self
在阻塞模式下产生。原始模式在块执行后恢复。
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
}
nonblock = boolean → boolean
当设定为在流启用非阻塞模式true
,并且当设定为阻塞模式false
。
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;
}
nonblock? → boolean
返回true
IO对象是否处于非阻塞模式。
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;
}
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
在内核中刷新输出缓冲区。
您必须要求'io/console'才能使用此方法。
static VALUE
console_oflush(VALUE io)
{
rb_io_t *fptr;
int fd;
GetOpenFile(io, fptr
fd = GetWriteFD(fptr
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
if (tcflush(fd, TCOFLUSH)) rb_sys_fail(0
#endif
(void)fd;
return io;
}
pathconf(p1)
使用fpathconf()返回路径名配置变量。
name
应该是一个Etc
始于其中的常量PC_
。
返回值是一个整数或零。零意味着无限期的限制。(fpathconf()返回-1,但未设置errno。)
require 'etc'
IO.pipe {|r, w|
p w.pathconf(Etc::PC_PIPE_BUF) #=> 4096
}
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
}
pid → integer
返回与ios
关联的子进程的进程ID 。这将由设置IO.popen
。
pipe = IO.popen("-")
if pipe
$stderr.puts "In parent, child pid is #{pipe.pid}"
else
$stderr.puts "In child, pid is #{$$}"
end
produces:
In child, pid is 26209
In parent, child pid is 26209
static VALUE
rb_io_pid(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr
if (!fptr->pid)
return Qnil;
return PIDT2NUM(fptr->pid
}
pos → integer
返回ios
的当前偏移量(以字节为单位)。
f = File.new("testfile")
f.pos #=> 0
f.gets #=> "This is line one\n"
f.pos #=> 17
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
}
pos = integer → integer
在ios中
寻找给定的位置(以字节为单位)。当ios
是textmode 时,不能保证找到正确的位置。
f = File.new("testfile")
f.pos = 17
f.gets #=> "This is line two\n"
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
}
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
将给定的对象写入ios
。返回nil
。
该流必须打开才能写入。每个给定的不是字符串的对象都将通过调用它的to_s
方法进行转换。当没有参数被调用时,打印内容$_
。
如果输出字段分隔符($,
)不是nil
,则将其插入对象之间。如果输出记录separator($\
)不是nil
,则会将其附加到输出。
$stdout.print("This is ", 100, " percent.\n")
生产:
This is 100 percent.
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;
}
printf(format_string , obj, ...) → nil
格式化并写入ios
,在格式字符串的控制下转换参数。详情请参阅Kernel#sprintf
。
VALUE
rb_io_printf(int argc, const VALUE *argv, VALUE out)
{
rb_io_write(out, rb_f_sprintf(argc, argv)
return Qnil;
}
putc(obj) → obj
如果OBJ
是Numeric
,写其代码是最不显著字节字符OBJ
,否则写的字符串表示的第一个字节OBJ
到IOS
。注意:此方法不适用于多字节字符,因为它会截断它们。
$stdout.putc "A"
$stdout.putc 65
生产:
AA
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;
}
puts(obj, ...) → nil
写入给定的对象(一个或多个),以IOS
与IO#print
。在没有以换行符结束的任何之后写入换行符。
如果使用数组参数调用,则将每个元素写入新行。如果不带参数调用,则输出一个换行符。
$stdout.puts("this", "is", "a", "test")
produces:
this
is
a
test
VALUE
rb_io_puts(int argc, const VALUE *argv, VALUE out)
{
int i;
VALUE line;
/* 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:
rb_io_write(out, line
if (RSTRING_LEN(line) == 0 ||
!str_end_with_asciichar(line, '\n')) {
rb_io_write(out, rb_default_rs
}
}
return Qnil;
}
raw(min: nil, time: nil) {|io| }
self
原始模式下的产量。
STDIN.raw(&:gets)
将读取并返回一个没有回显和行编辑的行。
您必须要求'io/console'才能使用此方法。
static VALUE
console_raw(int argc, VALUE *argv, VALUE io)
{
rawmode_arg_t opts, *optp = rawmode_opt(argc, argv, &opts
return ttymode(io, rb_yield, set_rawmode, optp
}
raw!(min: nil, time: nil)
启用原始模式。
如果终端模式需要返回,请使用io.raw {...}。
您必须要求'io/console'才能使用此方法。
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, &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;
}
read([length , outbuf]) → string, outbuf, or nil
从I/O流中读取长度
字节。
长度
必须是非负整数或nil
。
如果长度
是一个正整数,它会尝试读取长度
字节而不进行任何转换(二进制模式)。它返回nil
或一个字符串,其长度为
1至长度
字节。nil
意味着它在开始时遇到了EOF。1到长度为
-1字节的字符串表示在读取结果后它符合EOF。该长度
的字节串意味着它不符合EOF。结果字符串始终是ASCII-8BIT编码。
如果长度
被忽略或者是nil
,它将读取直到EOF和编码转换被应用。即使在开始时遇到EOF,它也会返回一个字符串。
如果长度
为零,则返回""
。
如果可选的outbuf
参数存在,它必须引用一个String,它将接收数据。该outbuf中
仅包含方法调用后接收到的数据,即使它不是在一开始是空的。
在文件结尾,它返回nil
或""
取决于长度ios
.read()和ios.read(nil)""
并返回。ios.read(positive-integer)
返回nil
。
f = File.new("testfile")
f.read(16) #=> "This is line one"
# reads whole file
open("file") {|f|
data = f.read # This returns a string even if the file is empty.
...
}
# iterate over fixed length records.
open("fixed-record-file") {|f|
while record = f.read(256)
...
end
}
# iterate over variable length records.
# record is prefixed by 32-bit length.
open("variable-record-file") {|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
}
请注意,此方法的行为与C中的fread()函数相同。这意味着它会重试以调用read(2)系统调用以读取具有指定长度(或直到EOF)的数据。即使ios
是非阻塞模式,此行为也会被保留。(与其他方法一样,此方法对非阻塞标志不敏感)。如果您需要像read read(2)系统调用那样的行为,请考虑readpartial,#read_nonblock和sysread。
static VALUE
io_read(int argc, VALUE *argv, VALUE io)
{
rb_io_t *fptr;
long n, len;
VALUE length, str;
#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
}
io_setstrbuf(&str,len
GetOpenFile(io, fptr
rb_io_check_byte_readable(fptr
if (len == 0) {
io_set_read_length(str, 0
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
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
if (previous_mode == O_TEXT) {
setmode(fptr->fd, O_TEXT
}
#endif
if (n == 0) return Qnil;
OBJ_TAINT(str
return str;
}
read_nonblock(maxlen , options) → string
read_nonblock(maxlen, outbuf , options) → outbuf
在为基础文件描述符设置O_NONBLOCK后,使用read(2)系统调用从ios
读取至多maxlen
字节。
如果可选的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在EOF上导致EOFError。
如果读取的字节缓冲区不是空的,#read_nonblock像readpartial那样从缓冲区读取数据。在这种情况下,不会调用read(2)系统调用。
当#read_nonblock引发一个IO::WaitReadable类型的异常时,在读取io以避免繁忙循环之前,不应调用#read_nonblock。这可以如下完成。
# emulates blocking read (readpartial).
begin
result = io.read_nonblock(maxlen)
rescue IO::WaitReadable
IO.select([io])
retry
end
尽管#read_nonblock不会引发IO::WaitWritable。OpenSSL::Buffering#read_nonblock可以引发IO::WaitWritable。如果IO和SSL应该多态使用,IO::WaitWritable也应该被救出。查看示例代码的OpenSSL::Buffering#read_nonblock文档。
请注意,除非设置了非阻塞标志,否则此方法与readpartial相同。
通过指定关键字参数异常
来false
,你可以指出#read_nonblock应该不会引发IO :: WaitReadable异常
,但返回的符号:wait_readable
来代替。在EOF中,它将返回nil而不是引发EOFError。
# File prelude.rb, line 75
def read_nonblock(len, buf = nil, exception: true)
__read_nonblock(len, buf, exception)
end
readbyte → integer
像读取一个字节一样IO#getbyte
,但会引起EOFError
文件结束。
static VALUE
rb_io_readbyte(VALUE io)
{
VALUE c = rb_io_getbyte(io
if (NIL_P(c)) {
rb_eof_error(
}
return c;
}
readchar → string
从ios
读取一个字符的字符串。引发EOFError
文件结尾。
f = File.new("testfile")
f.readchar #=> "h"
f.readchar #=> "e"
static VALUE
rb_io_readchar(VALUE io)
{
VALUE c = rb_io_getc(io
if (NIL_P(c)) {
rb_eof_error(
}
return c;
}
readline(sep=$/) → string
readline(limit) → string
readline(sep, limit) → string
读取一行IO#gets
,但引发EOFError
文件结束。
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;
}
readlines(sep=$/) → array
readlines(limit) → array
readlines(sep, limit) → array
读取ios中的
所有行,并将它们返回到数组中
。行由可选的sep
分隔。如果九月
是nil
,流的其余部分被返回为单个记录。如果第一个参数是一个整数,或者给出了可选的第二个参数,则返回的字符串不会超过以字节为单位的给定值。该流必须打开阅读或IOError
将被提出。
f = File.new("testfile")
f.readlines[0] #=> "This is line one\n"
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
}
readpartial(maxlen) → string
readpartial(maxlen, outbuf) → outbuf
从I / O流中最多读取maxlen
字节。它仅在ios
没有立即可用数据时阻塞。如果有一些数据可用,它不会阻止。如果可选的outbuf
参数存在,它必须引用一个String,它将接收数据。该outbuf中
仅包含方法调用后接收到的数据,即使它不是在一开始是空的。它EOFError
在文件结尾处引发。
readpartial是为诸如管道,套接字,tty等流设计的,只有当没有数据立即可用时才会阻塞。这意味着它只有在遵循所有条件时才会阻止。
- IO对象中的字节缓冲区为空。
- 流的内容是空的。
- 流未达到EOF。当读取部分块时,它等待流上的数据或EOF。如果达到某些数据,readpartial将返回数据。如果达到EOF,则readpartial引发EOFError。当readpartial不阻塞时,它立即返回或提升。如果字节缓冲区不是空的,它将返回缓冲区中的数据。否则,如果流有一些内容,它将返回流中的数据。否则,如果数据流达到EOF,则会引发EOFError.r,w = IO.pipe#buffer pipe content w <<“abc”#“”“abc”。r.readpartial(4096)#=>“abc”“”“”r.readpartial(4096)#blocks因为缓冲区和管道是空的。r,w = 10。readpartial(4096)#=>“ghi \ n”“”“”请注意,readpartial的行为类似于sysread。差异是:
- 如果字节缓冲区不为空,则从字节缓冲区读取而不是“缓冲IO(IOError)的系统读取”。
- 它不会导致Errno::EWOULDBLOCK和Errno::EINTR。当readpartial通过读系统调用遇到EWOULDBLOCK和EINTR时,readpartial重试系统调用。
后者意味着readpartial是非阻塞标志不敏感的。它阻止#sysread导致Errno::EWOULDBLOCK的情况,就好像fd是阻塞模式一样。
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;
}
ready? → true, false or nil
如果输入可用而不阻塞,则返回true;否则返回false。如果没有可用信息,则返回nil。
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;
}
reopen(other_IO) → ios
reopen(path, mode_str) → ios
将ios
与other_IO中
给出的I/O流重新关联,
或重新关联
到路径上
打开的新流。这可能动态地改变这个流的实际类别。
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"
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;
}
rewind → 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"
请注意,它不能用于诸如管道,ttys和套接字之类的流。
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
}
scanf(str) { |current_match| ... }
扫描当前字符串,直到匹配耗尽,在字符串中遇到每个匹配时产生每个匹配。一个块不是必需的,因为结果将被简单地聚合到最终的数组中。
"123 456".block_scanf("%d")
# => [123, 456]
如果给出了块,则从yield返回的值将被添加到输出数组中。
"123 456".block_scanf("%d") do |digit,| # the ',' unpacks the Array
digit + 100
end
# => [223, 556]
有关创建格式字符串的详细信息,请参阅Scanf。
你将需要'scanf'来使用#scanf。
# File lib/scanf.rb, line 613
def scanf(str,&b) #:yield: current_match
return block_scanf(str,&b) if b
return [] unless str.size > 0
start_position = pos rescue 0
matched_so_far = 0
source_buffer = ""
result_buffer = []
final_result = []
fstr = Scanf::FormatString.new(str)
loop do
if eof || (tty? &&! fstr.match(source_buffer))
final_result.concat(result_buffer)
break
end
source_buffer << gets
current_match = fstr.match(source_buffer)
spec = fstr.last_spec_tried
if spec.matched
if spec.mid_match?
result_buffer.replace(current_match)
next
end
elsif (fstr.matched_count == fstr.spec_count - 1)
if /\A\s*\z/.match(fstr.string_left)
break if spec.count_space?
result_buffer.replace(current_match)
next
end
end
final_result.concat(current_match)
matched_so_far += source_buffer.size
source_buffer.replace(fstr.string_left)
matched_so_far -= source_buffer.size
break if fstr.last_spec
fstr.prune
end
begin
seek(start_position + matched_so_far, IO::SEEK_SET)
rescue Errno::ESPIPE
end
soak_up_spaces if fstr.last_spec && fstr.space
return final_result
end
seek(amount, whence=IO::SEEK_SET) → 0 Show source
根据whence
的值寻找
流中给定的偏移anInteger
:
: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"
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
}
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
如果指定单参数,则从io读取的字符串将使用指定的编码进行标记。如果编码是以冒号分隔的两个编码名称“A:B”,则读取的字符串从编码A(外部编码)转换为编码B(内部编码),然后用B标记。如果指定了两个参数,则这些参数必须是编码对象或编码名称,第一个是外部编码,第二个是内部编码。如果指定了外部编码和内部编码,则可选散列参数指定转换选项。
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;
}
stat → stat
将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
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
}
sync → true or false
返回ios
的当前“同步模式” 。当同步模式为true时,所有输出将立即刷新到底层操作系统,而不会由Ruby在内部进行缓冲。另见IO#fsync
。
f = File.new("testfile")
f.sync #=> 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;
}
sync = boolean → boolean
将“同步模式”设置为true
或false
。当同步模式为真时,所有输出立即刷新到底层操作系统,而不会在内部进行缓冲。返回新的状态。另见IO#fsync
。
f = File.new("testfile")
f.sync = true
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;
}
sysread(maxlen, outbuf) → string
使用低级读取从ios
读取maxlen
字节并将其作为字符串返回。不要与从ios
读取的其他方法混用,否则可能会得到不可预知的结果。如果可选的outbuf
参数存在,它必须引用一个String,它将接收数据。该outbuf中
仅包含方法调用后接收到的数据,即使它不是在一开始是空的。在错误和文件结尾处引发。SystemCallErrorEOFError
f = File.new("testfile")
f.sysread(16) #=> "This is line one"
static VALUE
rb_io_sysread(int argc, VALUE *argv, VALUE io)
{
VALUE len, str;
rb_io_t *fptr;
long n, ilen;
struct read_internal_arg arg;
rb_scan_args(argc, argv, "11", &len, &str
ilen = NUM2LONG(len
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
rb_str_locktmp(str
arg.fd = fptr->fd;
arg.str_ptr = RSTRING_PTR(str
arg.len = ilen;
rb_ensure(read_internal_call, (VALUE)&arg, rb_str_unlocktmp, str
n = arg.len;
if (n == -1) {
rb_sys_fail_path(fptr->pathv
}
io_set_read_length(str, n
if (n == 0 && ilen > 0) {
rb_eof_error(
}
OBJ_TAINT(str
return str;
}
sysseek(offset, whence=IO::SEEK_SET) → integer
旨在给定偏移量
根据所述值的流中的何处
(参看IO#seek
为值何处
)。返回文件中的新偏移量
。
f = File.new("testfile")
f.sysseek(-13, IO::SEEK_END) #=> 53
f.sysread(10) #=> "And so on."
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 == -1 && errno) rb_sys_fail_path(fptr->pathv
return OFFT2NUM(pos
}
syswrite(string) → integer
使用低级写入将给定的字符串写入ios
。返回写入的字节数。不要与写入ios的
其他方法混用,否则可能会得到不可预知的结果。SystemCallError
错误引发。
f = File.new("out", "w")
f.syswrite("ABCDEF") #=> 6
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 == -1) rb_sys_fail_path(fptr->pathv
rb_str_tmp_frozen_release(str, tmp
return LONG2FIX(n
}
tell → integer
返回ios
的当前偏移量(以字节为单位)。
f = File.new("testfile")
f.pos #=> 0
f.gets #=> "This is line one\n"
f.pos #=> 17
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
}
to_i()
别名为:fileno
to_io → ios
返回ios
。
static VALUE
rb_io_to_io(VALUE io)
{
return io;
}
tty?→true或false显示来源
如果ios
与终端设备(tty)关联则返回true
,否则返回false
。
File.new("testfile").isatty #=> false
File.new("/dev/tty").isatty #=> true
static VALUE
rb_io_isatty(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr
if (isatty(fptr->fd) == 0)
return Qfalse;
return Qtrue;
}
ungetbyte(string) → nil
ungetbyte(integer) → nil
将字节(作为参数传递)推回到ios上
,以便随后的缓冲读取将返回它。在后续的读取操作之前,只有一个字节可能被推回(也就是说,您将只能读取已被推回的几个字节中的最后一个字节)。对未缓冲的读取(例如IO#sysread
)没有影响。
f = File.new("testfile") #=> #<File:testfile>
b = f.getbyte #=> 0x38
f.ungetbyte(b) #=> nil
f.getbyte #=> 0x38
VALUE
rb_io_ungetbyte(VALUE io, VALUE b)
{
rb_io_t *fptr;
GetOpenFile(io, fptr
rb_io_check_byte_readable(fptr
if (NIL_P(b)) return Qnil;
if (FIXNUM_P(b)) {
char cc = FIX2INT(b
b = rb_str_new(&cc, 1
}
else {
SafeStringValue(b
}
io_ungetbyte(b, fptr
return Qnil;
}
ungetc(string) → nil
将一个字符(作为参数传递)推回到ios上
,以便后续的缓存字符读取将返回它。在后续的读取操作之前,只有一个字符可能会被推回(也就是说,您将只能读取已被推回的几个字符中的最后一个字符)。对未缓冲的读取(例如IO#sysread
)没有影响。
f = File.new("testfile") #=> #<File:testfile>
c = f.getc #=> "8"
f.ungetc(c) #=> nil
f.getc #=> "8"
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;
}
wait(timeout = nil, mode = :read) → IO, true or nil
一直等到IO可读或可写,而不会阻塞并返回self
,或者nil
超时。true
缓冲数据可用时立即返回。可选参数mode
是一个:read
,:write
或:read_write
。
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;
}
wait_readable → IO, true or nil
wait_readable(timeout) → IO, true or nil
等到IO可读而没有阻塞并返回self
,或者nil
超时。缓冲数据可用时立即返回true
。
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;
}
wait_writable → IO
wait_writable(timeout) → IO or nil
等到IO可写且没有阻塞并返回self
或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;
}
winsize → rows, columns()
返回控制台大小。
您必须要求'io/console'才能使用此方法。
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))
}
winsize = rows, columns()
尝试设置控制台大小。效果取决于平台和运行环境。
您必须要求'io/console'才能使用此方法。
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;
#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"
}
if ((ws.dwSize.X < newcol && (ws.dwSize.X = newcol, 1)) ||
(ws.dwSize.Y < newrow && (ws.dwSize.Y = newrow, 1))) {
if (!SetConsoleScreenBufferSize(wh, ws.dwSize)) {
rb_syserr_fail(LAST_ERROR, "SetConsoleScreenBufferInfo"
}
}
ws.srWindow.Left = 0;
ws.srWindow.Top = 0;
ws.srWindow.Right = newcol;
ws.srWindow.Bottom = newrow;
if (!SetConsoleWindowInfo(wh, FALSE, &ws.srWindow)) {
rb_syserr_fail(LAST_ERROR, "SetConsoleWindowInfo"
}
#endif
return io;
}
write(string) → integer
将给定的字符串写入ios
。该流必须打开才能写入。如果参数不是字符串,它将被转换为使用的字符串to_s
。返回写入的字节数。
count = $stdout.write("This is a test\n")
puts "That was #{count} bytes of data"
produces:
This is a test
That was 15 bytes of data
static VALUE
io_write_m(VALUE io, VALUE str)
{
return io_write(io, str, 0
}
write_nonblock(string) → integer
write_nonblock(string , options) → integer
在为基础文件描述符设置O_NONBLOCK后,使用write(2)系统调用将给定的字符串写入ios
。
它返回写入的字节数。
#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)上,根据IO对象的种类不支持#write_nonblock。在这种情况下,#write_nonblock引发Errno::EBADF
。
通过指定关键字参数异常
来false
,你可以指出#write_nonblock应该不会引发IO :: WaitWritable异常
,但返回的符号:wait_writable
来代替。
# File prelude.rb, line 133
def write_nonblock(buf, exception: true)
__write_nonblock(buf, exception)
end
私有实例方法
block_scanf(str) { |current| ... }
# File lib/scanf.rb, line 681
def block_scanf(str)
final = []
# Sub-ideal, since another FS gets created in scanf.
# But used here to determine the number of specifiers.
fstr = Scanf::FormatString.new(str)
last_spec = fstr.last_spec
begin
current = scanf(str)
break if current.empty?
final.push(yield(current))
end until eof || fstr.last_spec_tried == last_spec
return final
end
soak_up_spaces()
# File lib/scanf.rb, line 672
def soak_up_spaces
c = getc
ungetc(c) if c
until eof ||! c || /\S/.match(c.chr)
c = getc
end
ungetc(c) if (c && /\S/.match(c.chr))
end