class IO

IO 类的一个实例(通常称为*流*)代表底层操作系统中的一个输入/输出流。IO 类是 Ruby 中输入和输出的基础。

File 是 Ruby 核心中唯一一个 IO 的子类。Ruby 标准库中的一些类也是 IO 的子类;这些类包括 TCPSocketUDPSocket

全局常量 ARGF(也可通过 $< 访问)提供了一个类似 IO 的流,允许访问 ARGV 中找到的所有文件路径(或者如果 ARGV 为空,则访问 STDIN)。ARGF 本身并不是 IO 的子类。

StringIO 提供了一个类似 IO 的流,它处理一个 StringStringIO 本身并不是 IO 的子类。

基于 IO 的重要对象包括

可以使用以下方法创建 IO 类的实例

File 流一样,IO 流具有

并且像其他 IO 流一样,它具有

扩展 io/console

扩展 io/console 提供了许多与控制台交互的方法;需要它会在 IO 类中添加许多方法。

示例文件

这里的许多示例使用这些变量

# English text with newlines.
text = <<~EOT
  First line
  Second line

  Fourth line
  Fifth line
EOT

# Russian text.
russian = "\u{442 435 441 442}" # => "тест"

# Binary data.
data = "\u9990\u9991\u9992\u9993\u9994"

# Text file.
File.write('t.txt', text)

# File with Russian text.
File.write('t.rus', russian)

# File with binary data.
f = File.new('t.dat', 'wb:UTF-16')
f.write(data)
f.close

打开选项

许多 IO 方法接受可选的关键字参数,这些参数决定了新流的打开方式

还可以使用 String#encode 中提供的选项,这些选项可以控制外部和内部编码之间的转换。

基本 IO

您可以使用这些方法执行基本流 IO,这些方法通常在多字节字符串上操作

位置

IO 流有一个非负整数*位置*,这是下一次读写将发生的字节偏移量。新流的位置为零(行号也为零);rewind 方法将位置(以及行号)重置为零。

这些方法将丢弃*缓冲区*和用于该 IO 的 Encoding::Converter 实例。

相关方法

打开和关闭的流

新的 IO 流可以为读取打开、为写入打开或两者都打开。

当流被垃圾回收器回收时,它会被自动关闭。

尝试在已关闭的流上读取或写入会引发异常。

相关方法

流末尾

您可以查询流是否位于其末尾

您可以使用方法 IO#seek 定位到流末尾

f = File.new('t.txt')
f.eof? # => false
f.seek(0, :END)
f.eof? # => true
f.close

或者通过读取所有流内容(这比使用 IO#seek 慢)

f.rewind
f.eof? # => false
f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
f.eof? # => true

行 IO

IO 类支持面向行的*输入*和*输出*

行输入

IO 类支持*文件*的面向行的输入和*IO 流*的面向行的输入

文件行输入

您可以使用以下方法从文件中读取行

对于这些方法中的每一种

流行输入

您可以使用以下方法从 IO 流中读取行

对于这些方法中的每一种

行分隔符

每个*行输入方法*都使用一个*行分隔符*:决定什么被视为一行的字符串;它有时被称为*输入记录分隔符*。

默认的行分隔符取自全局变量 $/,其初始值为 "\n"

通常,下一行读取的内容是从当前*位置*到下一个行分隔符的所有数据(但参见 特殊行分隔符值)。

f = File.new('t.txt')
# Method gets with no sep argument returns the next line, according to $/.
f.gets # => "First line\n"
f.gets # => "Second line\n"
f.gets # => "\n"
f.gets # => "Fourth line\n"
f.gets # => "Fifth line\n"
f.close

您可以通过传递参数 sep 来使用不同的行分隔符

f = File.new('t.txt')
f.gets('l')   # => "First l"
f.gets('li')  # => "ine\nSecond li"
f.gets('lin') # => "ne\n\nFourth lin"
f.gets        # => "e\n"
f.close

或通过设置全局变量 $/

f = File.new('t.txt')
$/ = 'l'
f.gets # => "First l"
f.gets # => "ine\nSecond l"
f.gets # => "ine\n\nFourth l"
f.close
特殊行分隔符值

*行输入方法*中的每一种都接受 sep 参数的两个特殊值

行限制

*行输入方法*中的每一种都使用一个整数*行限制*,它限制了可以返回的字节数。(多字节字符不会被分割,因此返回的行可能比限制稍长)。

默认限制值为 -1;任何负的限制值意味着没有限制。

如果没有限制,行仅由 sep 决定。

# Text with 1-byte characters.
File.open('t.txt') {|f| f.gets(1) }  # => "F"
File.open('t.txt') {|f| f.gets(2) }  # => "Fi"
File.open('t.txt') {|f| f.gets(3) }  # => "Fir"
File.open('t.txt') {|f| f.gets(4) }  # => "Firs"
# No more than one line.
File.open('t.txt') {|f| f.gets(10) } # => "First line"
File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
File.open('t.txt') {|f| f.gets(12) } # => "First line\n"

# Text with 2-byte characters, which will not be split.
File.open('t.rus') {|f| f.gets(1).size } # => 1
File.open('t.rus') {|f| f.gets(2).size } # => 1
File.open('t.rus') {|f| f.gets(3).size } # => 2
File.open('t.rus') {|f| f.gets(4).size } # => 2
行分隔符和行限制

给定 seplimit 参数时,组合了这两种行为

示例

File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
File.open('t.txt') {|f| f.gets('li', 2) }  # => "Fi"
行号

可读的 IO 流有一个非负整数*行号*

除非通过调用方法 IO#lineno= 修改,否则行号是根据有效的*行分隔符*由某些面向行的方**法读取的行数。

新流最初的行号为零(位置也为零);rewind 方法将行号(以及位置)重置为零。

f = File.new('t.txt')
f.lineno # => 0
f.gets   # => "First line\n"
f.lineno # => 1
f.rewind
f.lineno # => 0
f.close

从流中读取行通常会改变其行号。

f = File.new('t.txt', 'r')
f.lineno   # => 0
f.readline # => "This is line one.\n"
f.lineno   # => 1
f.readline # => "This is the second line.\n"
f.lineno   # => 2
f.readline # => "Here's the third line.\n"
f.lineno   # => 3
f.eof?     # => true
f.close

迭代流中的行通常会改变其行号。

File.open('t.txt') do |f|
  f.each_line do |line|
    p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
  end
end

输出

"position=11 eof?=false lineno=1"
"position=23 eof?=false lineno=2"
"position=24 eof?=false lineno=3"
"position=36 eof?=false lineno=4"
"position=47 eof?=true lineno=5"

与流的*位置*不同,行号不影响下一次读写的位置。

f = File.new('t.txt')
f.lineno = 1000
f.lineno # => 1000
f.gets   # => "First line\n"
f.lineno # => 1001
f.close

与行号相关的是全局变量 $.

行输出

您可以使用以下方法逐行写入 IO 流

字符 IO

您可以使用这些方法逐个字符地处理 IO 流

字节 IO

您可以使用这些方法逐个字节地处理 IO 流

代码点 IO

您可以逐个代码点地处理 IO 流

这里有什么

首先,其他部分。类 IO

在此,IO 类提供了对以下方面有用的方法

创建

读取

写入

定位

迭代

设置

查询

Buffering

低级访问

其他