class StringIO

类 StringIO 支持将字符串作为流来访问,在某些方面类似于 类 IO

您可以使用以下方式创建 StringIO 实例:

与 IO 流一样,StringIO 流具有某些属性:

关于示例

本页上的示例假定已加载 StringIO

require 'stringio'

并且已定义此常量

TEXT = <<EOT
First line
Second line

Fourth line
Fifth line
EOT

流属性

读/写模式

摘要

模式 初始清空? 读取 写入
'r':只读 任何位置 Error
'w':只写 Error 任何位置
'a':仅追加 Error 仅末尾
'r+':读/写 任何位置 任何位置
'w+':读/写 任何位置 任何位置
'a+':读/追加 任何位置 仅末尾

下面的每个部分都描述了一种读/写模式。

任何模式都可以作为字符串或文件常量给出;例如

strio = StringIO.new('foo', 'a')
strio = StringIO.new('foo', File::WRONLY | File::APPEND)

'r':只读

模式指定为以下之一:

初始状态

strio = StringIO.new('foobarbaz', 'r')
strio.pos    # => 0            # Beginning-of-stream.
strio.string # => "foobarbaz"  # Not cleared.

可以在任何位置读取

strio.gets(3) # => "foo"
strio.gets(3) # => "bar"
strio.pos = 9
strio.gets(3) # => nil

不能写入

strio.write('foo')  # Raises IOError: not opened for writing

'w':只写

模式指定为以下之一:

初始状态

strio = StringIO.new('foo', 'w')
strio.pos    # => 0   # Beginning of stream.
strio.string # => ""  # Initially cleared.

可以在任何位置写入(即使超过流末尾)

strio.write('foobar')
strio.string # => "foobar"
strio.rewind
strio.write('FOO')
strio.string # => "FOObar"
strio.pos = 3
strio.write('BAR')
strio.string # => "FOOBAR"
strio.pos = 9
strio.write('baz')
strio.string # => "FOOBAR\u0000\u0000\u0000baz"  # Null-padded.

不能读取

strio.read  # Raises IOError: not opened for reading

'a':仅追加

模式指定为以下之一:

初始状态

strio = StringIO.new('foo', 'a')
strio.pos    # => 0      # Beginning-of-stream.
strio.string # => "foo"  # Not cleared.

只能在末尾写入;位置不影响写入

strio.write('bar')
strio.string # => "foobar"
strio.write('baz')
strio.string # => "foobarbaz"
strio.pos = 400
strio.write('bat')
strio.string # => "foobarbazbat"

不能读取

strio.gets  # Raises IOError: not opened for reading

'r+':读/写

模式指定为以下之一:

初始状态

strio = StringIO.new('foobar', 'r+')
strio.pos    # => 0         # Beginning-of-stream.
strio.string # => "foobar"  # Not cleared.

可以在任何位置写入(即使超过流末尾)

strio.write('FOO')
strio.string # => "FOObar"
strio.write('BAR')
strio.string # => "FOOBAR"
strio.write('BAZ')
strio.string # => "FOOBARBAZ"
strio.pos = 12
strio.write('BAT')
strio.string # => "FOOBARBAZ\u0000\u0000\u0000BAT"  # Null padded.

可以在任何位置读取

strio.pos = 0
strio.gets(3) # => "FOO"
strio.pos = 6
strio.gets(3) # => "BAZ"
strio.pos = 400
strio.gets(3) # => nil

'w+':读/写(初始清空)

模式指定为以下之一:

初始状态

strio = StringIO.new('foo', 'w+')
strio.pos    # => 0   # Beginning-of-stream.
strio.string # => ""  # Truncated.

可以在任何位置写入(即使超过流末尾)

strio.write('foobar')
strio.string # => "foobar"
strio.rewind
strio.write('FOO')
strio.string # => "FOObar"
strio.write('BAR')
strio.string # => "FOOBAR"
strio.write('BAZ')
strio.string # => "FOOBARBAZ"
strio.pos = 12
strio.write('BAT')
strio.string # => "FOOBARBAZ\u0000\u0000\u0000BAT"  # Null-padded.

可以在任何位置读取

strio.rewind
strio.gets(3) # => "FOO"
strio.gets(3) # => "BAR"
strio.pos = 12
strio.gets(3) # => "BAT"
strio.pos = 400
strio.gets(3) # => nil

'a+':读/追加

模式指定为以下之一:

初始状态

strio = StringIO.new('foo', 'a+')
strio.pos    # => 0      # Beginning-of-stream.
strio.string # => "foo"  # Not cleared.

只能在末尾写入;rewind;位置不影响写入

strio.write('bar')
strio.string # => "foobar"
strio.write('baz')
strio.string # => "foobarbaz"
strio.pos = 400
strio.write('bat')
strio.string # => "foobarbazbat"

可以在任何位置读取

strio.rewind
strio.gets(3) # => "foo"
strio.gets(3) # => "bar"
strio.pos = 9
strio.gets(3) # => "bat"
strio.pos = 400
strio.gets(3) # => nil

Data 模式

要指定流被视为文本还是二进制数据,可以在上面的任何字符串读/写模式后附加以下任一选项:

如果未指定,则流默认为文本数据。

示例

strio = StringIO.new('foo', 'rt')
strio.external_encoding # => #<Encoding:UTF-8>
data = "\u9990\u9991\u9992\u9993\u9994"
strio = StringIO.new(data, 'rb')
strio.external_encoding # => #<Encoding:BINARY (ASCII-8BIT)>

指定数据模式时,不能省略读/写模式。

StringIO.new(data, 'b')  # Raises ArgumentError: invalid access mode b

可以通过调用实例方法 binmode 将文本流更改为二进制;二进制流不能更改为文本。

编码

流具有编码;参见 编码

新流或重新打开的流的初始编码取决于其 数据模式

以下实例方法很有用:

示例

strio = StringIO.new('foo', 'rt')  # Text mode.
strio.external_encoding # => #<Encoding:UTF-8>
data = "\u9990\u9991\u9992\u9993\u9994"
strio = StringIO.new(data, 'rb') # Binary mode.
strio.external_encoding # => #<Encoding:BINARY (ASCII-8BIT)>
strio = StringIO.new('foo')
strio.external_encoding # => #<Encoding:UTF-8>
strio.set_encoding('US-ASCII')
strio.external_encoding # => #<Encoding:US-ASCII>

位置

流有一个 *位置*,即流中的字节偏移量。流的初始位置为零。

获取和设置位置

以下每个方法都会初始化(设置为零)新流或重新打开的流的位置:

以下每个方法都会查询、获取或设置位置,而不会更改流的其他属性:

示例

strio = StringIO.new('foobar')
strio.pos  # => 0
strio.pos = 3
strio.pos  # => 3
strio.eof? # => false
strio.rewind
strio.pos  # => 0
strio.seek(0, IO::SEEK_END)
strio.pos  # => 6
strio.eof? # => true

读取前后的位置

除了 pread,流的读取方法(参见 基本读取)从当前位置开始读取。

除了 pread,读取方法会使位置前进到读取的子字符串之后。

示例

strio = StringIO.new(TEXT)
strio.string # => "First line\nSecond line\n\nFourth line\nFifth line\n"
strio.pos    # => 0
strio.getc   # => "F"
strio.pos    # => 1
strio.gets   # => "irst line\n"
strio.pos    # => 11
strio.pos = 24
strio.gets   # => "Fourth line\n"
strio.pos    # => 36

strio = StringIO.new('тест') # Four 2-byte characters.
strio.pos = 0 # At first byte of first character.
strio.read    # => "тест"
strio.pos = 1 # At second byte of first character.
strio.read    # => "\x82ест"
strio.pos = 2 # At first of second character.
strio.read    # => "ест"

strio = StringIO.new(TEXT)
strio.pos = 15
a = []
strio.each_line {|line| a.push(line) }
a         # => ["nd line\n", "\n", "Fourth line\n", "Fifth line\n"]
strio.pos # => 47  ## End-of-stream.

写入前后的位置

以下每个方法都会在当前位置开始写入,并将位置前进到写入的子字符串的末尾:

示例

strio = StringIO.new('foo')
strio.pos    # => 0
strio.putc('b')
strio.string # => "boo"
strio.pos    # => 1
strio.write('r')
strio.string # => "bro"
strio.pos    # => 2
strio.puts('ew')
strio.string # => "brew\n"
strio.pos    # => 5
strio.pos = 8
strio.write('foo')
strio.string # => "brew\n\u0000\u0000\u0000foo"
strio.pos    # => 11

以下每个方法都会在当前位置 *之前* 写入,并使位置递减,以便下一个读取的数据是刚刚写入的数据:

示例

strio = StringIO.new('foo')
strio.pos = 2
strio.ungetc('x')
strio.pos    # => 1
strio.string # => "fxo"
strio.ungetc('x')
strio.pos    # => 0
strio.string # => "xxo"

此方法不影响位置:

示例

strio = StringIO.new('foobar')
strio.pos    # => 0
strio.truncate(3)
strio.string # => "foo"
strio.pos    # => 0
strio.pos = 500
strio.truncate(0)
strio.string # => ""
strio.pos    # => 500

行号

流有一个行号,初始为零。

行号会受到读取的影响(但从不受写入影响);通常,每次读取记录分隔符(默认:"\n")时,行号都会递增。

示例

strio = StringIO.new(TEXT)
strio.string # => "First line\nSecond line\n\nFourth line\nFifth line\n"
strio.lineno # => 0
strio.gets   # => "First line\n"
strio.lineno # => 1
strio.getc   # => "S"
strio.lineno # => 1
strio.gets   # => "econd line\n"
strio.lineno # => 2
strio.gets   # => "\n"
strio.lineno # => 3
strio.gets   # => "Fourth line\n"
strio.lineno # => 4

设置位置不会影响行号。

strio.pos = 0
strio.lineno # => 4
strio.gets   # => "First line\n"
strio.pos    # => 11
strio.lineno # => 5

设置行号也不会影响位置。

strio.lineno = 10
strio.pos    # => 11
strio.gets   # => "Second line\n"
strio.lineno # => 11
strio.pos    # => 23

打开/关闭的流

新流为读取或写入而打开,并且可以同时为两者打开;参见 读/写模式

以下每个方法都会初始化新流或重新打开的流的读/写模式。

其他相关方法

BOM(字节顺序标记)

::new::openreopen 提供的字符串可能在字符串开头包含一个可选的 BOM(字节顺序标记);BOM 会影响流的编码。

BOM(如果提供)

utf8_bom = "\xEF\xBB\xBF"
string = utf8_bom + 'foo'
string.bytes               # => [239, 187, 191, 102, 111, 111]
strio.string.bytes.take(3) # => [239, 187, 191]                  # The BOM.
strio = StringIO.new(string, 'rb')
strio.string.bytes         # => [239, 187, 191, 102, 111, 111]   # BOM is part of the stored string.
strio.external_encoding    # => #<Encoding:BINARY (ASCII-8BIT)>  # Default for a binary stream.
strio.gets                 # => "\xEF\xBB\xBFfoo"                # BOM is part of the stream.

您可以调用实例方法 set_encoding_by_bom 来“激活”存储的 BOM;执行此操作后,BOM:

strio.set_encoding_by_bom
strio.string.bytes      # => [239, 187, 191, 102, 111, 111]  # BOM is still part of the stored string.
strio.external_encoding # => #<Encoding:UTF-8>               # The new encoding.
strio.rewind            # => 0
strio.gets              # => "foo"                           # BOM is not part of the stream.

基本流 IO

基本读取

您可以使用以下实例方法从流中读取:

您可以使用以下实例方法遍历流:

此实例方法在多线程应用程序中很有用:

基本写入

您可以使用以下实例方法向流写入,并使位置前进:

您可以使用以下实例方法“取消入栈”到流中;每个方法都会在当前位置 *之前* 写入,并使位置递减,以便下一个读取的数据是刚刚写入的数据。

另一个写入方法

行 IO

读取

写入

字符 IO

读取

写入

字节 IO

读取

写入

代码点 IO

读取