StringIO 클래스
StringIO 클래스
문자열을 스트림(stream)처럼 다루고 싶을 때 쓰는 클래스가 StringIO예요. IO 클래스와 비슷한 점이 많은데, 실제 파일 대신 메모리 안의 문자열을 대상으로 한다는 점만 달라요.
출처: Ruby 4.0 API
본문
클래스 StringIO는 문자열을 스트림으로 접근할 수 있게 해 줘요. 여러모로 IO 클래스와 비슷하죠.
StringIO 인스턴스는 이렇게 만들 수 있어요:
StringIO.new: 주어진 문자열을 담은 새StringIO객체를 반환해요.StringIO.open: 새StringIO객체를 주어진 블록에 넘겨요.
IO 스트림처럼 StringIO 스트림도 몇 가지 속성을 가져요:
- 읽기/쓰기 모드: 스트림을 읽을 수 있는지, 쓸 수 있는지, 추가만 할 수 있는지 등을 결정해요. Read/Write Mode 참고.
- 데이터 모드: 텍스트 전용인지 바이너리인지. Data Mode 참고.
- 인코딩: 내부·외부 인코딩. Encodings 참고.
- 위치(position): 스트림에서 다음 읽기/쓰기가 일어날 위치. Position 참고.
- 줄 번호: 줄 단위의 특별한 "위치"(위의 position과는 달라요). Line Number 참고.
- 열림/닫힘: 스트림이 읽기·쓰기용으로 열려 있는지 닫혀 있는지. Open/Closed Streams 참고.
- BOM: 바이트 순서 표시(byte order mark). Byte Order Mark 참고.
예시에 관해 (About the Examples)
이 페이지의 예시는 StringIO가 require되어 있다고 가정해요:
require 'stringio'
그리고 이 상수가 정의되어 있다고 가정해요:
TEXT = <<EOT
First line
Second line
Fourth line
Fifth line
EOT
스트림 속성 (Stream Properties)
읽기/쓰기 모드 (Read/Write Mode)
요약 (Summary)
| 모드 | 초기 클리어? | 읽기 | 쓰기 |
|---|---|---|---|
| 'r': 읽기 전용 | No | 아무데나 | Error |
| 'w': 쓰기 전용 | Yes | Error | 아무데나 |
| 'a': 추가 전용 | No | Error | 끝만 |
| 'r+': 읽기/쓰기 | No | 아무데나 | 아무데나 |
| 'w+': 읽기-쓰기 | Yes | 아무데나 | 아무데나 |
| 'a+': 읽기/추가 | No | 아무데나 | 끝만 |
아래 각 절이 읽기/쓰기 모드를 설명해요.
어느 모드든 문자열로 주거나 파일 상수로 줄 수 있어요. 예를 들면:
strio = StringIO.new('foo', 'a')
strio = StringIO.new('foo', File::WRONLY | File::APPEND)
'r': 읽기 전용 (Read-Only)
모드 지정:
- 문자열:
'r'. - 상수:
File::RDONLY.
초기 상태:
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': 쓰기 전용 (Write-Only)
모드 지정:
- 문자열:
'w'. - 상수:
File::WRONLY.
초기 상태:
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': 추가 전용 (Append-Only)
모드 지정:
- 문자열:
'a'. - 상수:
File::WRONLY | File::APPEND.
초기 상태:
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+': 읽기/쓰기 (Read/Write)
모드 지정:
- 문자열:
'r+'. - 상수:
File::RDRW.
초기 상태:
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+': 읽기/쓰기 (초기 클리어)
모드 지정:
- 문자열:
'w+'. - 상수:
File::RDWR | File::TRUNC.
초기 상태:
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+': 읽기/추가 (Read/Append)
모드 지정:
- 문자열:
'a+'. - 상수:
File::RDWR | File::APPEND.
초기 상태:
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 Mode)
스트림을 텍스트로 다룰지 바이너리 데이터로 다룰지 지정하려면, 위의 문자열 읽기/쓰기 모드 어느 것에든 다음 중 하나를 붙이면 돼요:
't': 텍스트. 인코딩을Encoding::UTF_8로 초기화해요.'b': 바이너리. 인코딩을Encoding::ASCII_8BIT로 초기화해요.
둘 다 주지 않으면 기본적으로 텍스트 데이터로 처리돼요.
예시:
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로 바이너리로 바꿀 수 있어요. 하지만 바이너리 스트림을 텍스트로 바꿀 수는 없어요.
인코딩 (Encodings)
스트림에는 인코딩이 있어요. Encodings 참고.
새로 만들거나 다시 연 스트림의 초기 인코딩은 데이터 모드에 따라 달라요:
- 텍스트:
Encoding::UTF_8. - 바이너리:
Encoding::ASCII_8BIT.
관련 인스턴스 메서드:
external_encoding: 스트림의 현재 인코딩을Encoding객체로 반환해요.internal_encoding:nil을 반환해요. 스트림에는 내부 인코딩이 없어요.set_encoding: 스트림의 인코딩을 설정해요.set_encoding_by_bom: 스트림의 인코딩을 스트림의 BOM(바이트 순서 표시)으로 설정해요.
예시:
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>
위치 (Position)
스트림에는 위치(position) 가 있어요. 스트림 안의 정수 오프셋(바이트 단위)이죠. 스트림의 초기 위치는 0이에요.
위치 가져오기와 설정하기
이 메서드들은 새로 만들거나 다시 연 스트림의 위치를 (0으로) 초기화해요:
::new: 새 스트림을 반환해요.::open: 새 스트림을 블록에 넘겨요.reopen: 스트림을 다시 초기화해요.
이 메서드들은 스트림을 바꾸지 않으면서 위치를 조회·가져오기·설정해요:
eof?: 위치가 스트림 끝인지 여부를 반환해요.pos: 위치를 반환해요.pos=: 위치를 설정해요.rewind: 위치를 0으로 설정해요.seek: 위치를 설정해요.
예시:
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 # => "ест"
쓰기 전후의 위치
이 메서드들은 현재 위치에서 쓰기를 시작하고, 쓴 부분 문자열의 끝까지 위치를 옮겨요:
putc: 주어진 문자를 써요.write: 주어진 객체들을 문자열로 써요.Kernel#puts: 주어진 객체들을 문자열로 쓰되 각각 개행을 붙여요.
예시:
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
이 메서드들은 현재 위치 앞에 쓰고, 위치를 감소시켜서 쓴 데이터가 다음에 읽히게 해요:
ungetbyte: 주어진 바이트를 앞으로 밀어 넣어요(unshift).ungetc: 주어진 문자를 앞으로 밀어 넣어요.
예시:
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"
위치에 영향을 주지 않는 메서드:
truncate: 스트림의 문자열을 주어진 크기로 잘라요.
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
줄 번호 (Line Number)
스트림에는 줄 번호가 있어요. 처음에는 0이에요:
lineno메서드가 줄 번호를 반환해요.lineno=메서드가 줄 번호를 설정해요.
줄 번호는 읽기에 영향을 받을 수 있어요(쓰기에는 안 받음). 일반적으로 레코드 구분자(기본값: "\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
열림/닫힘 (Open/Closed Streams)
새 스트림은 읽기 또는 쓰기 중 하나로 열려 있고, 둘 다로 열려 있을 수도 있어요. 읽기/쓰기 모드 참고.
이 메서드들은 새로 만들거나 다시 연 스트림의 읽기/쓰기 모드를 초기화해요:
::new: 새 스트림을 반환해요.::open: 새 스트림을 블록에 넘겨요.reopen: 스트림을 다시 초기화해요.
관련 메서드들:
close: 읽기와 쓰기 둘 다 닫아요.close_read: 읽기만 닫아요.close_write: 쓰기만 닫아요.closed?: 읽기·쓰기 둘 다 닫혔는지 여부를 반환해요.closed_read?: 읽기로 닫혔는지 여부를 반환해요.closed_write?: 쓰기로 닫혔는지 여부를 반환해요.
BOM (바이트 순서 표시)
::new, ::open, reopen에 주는 문자열은 시작 부분에 선택적 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, 102, 111, 111] # 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 (Basic Stream IO)
기본 읽기 (Basic Reading)
이 인스턴스 메서드들로 스트림에서 읽을 수 있어요:
getbyte: 다음 바이트를 읽고 반환해요.getc: 다음 문자를 읽고 반환해요.gets: 다음 줄의 전체 또는 일부를 읽고 반환해요.read: 스트림에 남은 데이터의 전체 또는 일부를 읽고 반환해요.readlines: 스트림에 남은 데이터를 읽고 그 줄들의 배열을 반환해요.Kernel#readline:gets와 같지만 스트림 끝이면 예외를 발생시켜요.
이 인스턴스 메서드들로 스트림을 반복할 수 있어요:
each_byte: 남은 각 바이트를 읽어 블록에 넘겨요.each_char: 남은 각 문자를 읽어 블록에 넘겨요.each_codepoint: 남은 각 코드포인트를 읽어 블록에 넘겨요.each_line: 남은 각 줄의 전체 또는 일부를 읽어 블록에 넘겨요.
멀티스레드 앱에서 유용한 인스턴스 메서드:
pread: 스트림의 전체 또는 일부를 읽고 반환해요.
기본 쓰기 (Basic Writing)
위치를 옮기며 스트림에 쓸 수 있는 인스턴스 메서드들:
putc: 주어진 문자를 써요.write: 주어진 객체들을 문자열로 써요.Kernel#puts: 주어진 객체들을 문자열로 쓰되 각각 개행을 붙여요.
"unshift"하는 인스턴스 메서드들. 각각 현재 위치 앞에 쓰고 위치를 감소시켜서 쓴 데이터가 다음에 읽히게 해요:
ungetbyte: 주어진 바이트를 밀어 넣어요.ungetc: 주어진 문자를 밀어 넣어요.
쓰기 메서드 하나 더:
truncate: 스트림의 문자열을 주어진 크기로 잘라요.
줄 IO (Line IO)
읽기:
gets: 다음 줄을 읽고 반환해요.Kernel#readline:gets와 같지만 스트림 끝이면 예외를 발생시켜요.readlines: 스트림에 남은 데이터를 읽고 줄 배열을 반환해요.each_line: 남은 각 줄을 읽어 블록에 넘겨요.
쓰기:
Kernel#puts: 주어진 객체들을 쓰되 각각 개행을 붙여요.
문자 IO (Character IO)
읽기:
each_char: 남은 각 문자를 읽어 블록에 넘겨요.getc: 다음 문자를 읽고 반환해요.
쓰기:
putc: 주어진 문자를 써요.ungetc: 주어진 문자를 밀어 넣어요.
바이트 IO (Byte IO)
읽기:
each_byte: 남은 각 바이트를 읽어 블록에 넘겨요.getbyte: 다음 바이트를 읽고 반환해요.
쓰기:
ungetbyte: 주어진 바이트를 밀어 넣어요.
코드포인트 IO (Codepoint IO)
읽기:
each_codepoint: 남은 각 코드포인트를 읽어 블록에 넘겨요.
Class Methods
new(string = '', mode = 'r+') → new_stringio
string과 mode로 만들어진 새 StringIO 인스턴스를 반환해요. 더 이상 필요 없을 때 닫아야 해요:
strio = StringIO.new
strio.string # => ""
strio.closed_read? # => false
strio.closed_write? # => false
strio.close
string이 frozen이면 기본 mode는 'r'이에요:
strio = StringIO.new('foo'.freeze)
strio.string # => "foo"
strio.closed_read? # => false
strio.closed_write? # => true
strio.close
mode 인자는 유효한 접근 모드여야 해요. 문자열이거나 정수 상수일 수 있어요:
StringIO.new('foo', 'w+')
StringIO.new('foo', File::RDONLY)
관련: StringIO.open(StringIO 객체를 블록에 넘기고, 블록 종료 시 자동으로 닫음).
open(string = '', mode = 'r+') → new_stringio
StringIO.new(string, mode)을 호출해 새 StringIO 인스턴스를 만들어요.
블록이 없으면 새 인스턴스를 반환해요:
strio = StringIO.open # => #<StringIO>
블록을 주면 새 인스턴스와 함께 블록을 호출하고 블록의 값을 반환해요. 블록 종료 시 인스턴스를 닫아요:
StringIO.open('foo') {|strio| strio.string.upcase } # => "FOO"
관련: StringIO.new.
Instance Methods
binmode → self
self의 데이터 모드를 바이너리 모드로 설정해요. Data Mode 참고.
close → nil
읽기와 쓰기 둘 다 닫고 nil을 반환해요:
strio = StringIO.new
strio.closed? # => false
strio.close # => nil
strio.closed? # => true
strio.read # Raises IOError: not opened for reading
strio.write # Raises IOError: not opened for writing
관련: StringIO#close_read, StringIO#close_write, StringIO.closed?.
close_read → nil
읽기만 닫고 nil을 반환해요. 쓰기 닫힘 설정은 그대로 남아요:
strio = StringIO.new
strio.closed_read? # => false
strio.close_read # => nil
strio.closed_read? # => true
strio.closed_write? # => false
strio.read # Raises IOError: not opened for reading
close_write → nil
쓰기만 닫고 nil을 반환해요. 읽기 닫힘 설정은 그대로 남아요:
strio = StringIO.new
strio.closed_write? # => false
strio.close_write # => nil
strio.closed_write? # => true
strio.closed_read? # => false
strio.write('foo') # Raises IOError: not opened for writing
closed? → true or false
읽기·쓰기 둘 다 닫혔는지 여부를 반환해요:
strio = StringIO.new
strio.closed? # => false # Open for reading and writing.
strio.close_read
strio.closed? # => false # Still open for writing.
strio.close_write
strio.closed? # => true # Now closed for both.
closed_read? → true or false
읽기로 닫혔는지 여부를 반환해요:
strio = StringIO.new
strio.closed_read? # => false
strio.close_read
strio.closed_read? # => true
closed_write? → true or false
쓰기로 닫혔는지 여부를 반환해요:
strio = StringIO.new
strio.closed_write? # => false
strio.close_write
strio.closed_write? # => true
each_byte { |byte| ... } → self
블록을 주면 스트림의 남은 각 바이트마다 블록을 호출하고, 스트림을 파일 끝에 위치시키고 self를 반환해요:
bytes = []
strio = StringIO.new('hello') # Five 1-byte characters.
strio.each_byte {|byte| bytes.push(byte) }
strio.eof? # => true
bytes # => [104, 101, 108, 108, 111]
bytes = []
strio = StringIO.new('тест') # Four 2-byte characters.
strio.each_byte {|byte| bytes.push(byte) }
bytes # => [209, 130, 208, 181, 209, 129, 209, 130]
bytes = []
strio = StringIO.new('こんにちは') # Five 3-byte characters.
strio.each_byte {|byte| bytes.push(byte) }
bytes # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
스트림 위치가 중요해요:
bytes = []
strio = StringIO.new('こんにちは')
strio.getc # => "こ"
strio.pos # => 3 # 3-byte character was read.
strio.each_byte {|byte| bytes.push(byte) }
bytes # => [227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
파일 끝에 있으면 블록을 호출하지 않아요:
strio.eof? # => true
strio.each_byte {|byte| fail 'Boo!' }
strio.eof? # => true
블록이 없으면 새 Enumerator를 반환해요.
each_char { |char| ... } → self
블록을 주면 스트림의 남은 각 문자마다 블록을 호출하고, 스트림을 파일 끝에 위치시키고 self를 반환해요:
chars = []
strio = StringIO.new('hello')
strio.each_char {|char| chars.push(char) }
strio.eof? # => true
chars # => ["h", "e", "l", "l", "o"]
chars = []
strio = StringIO.new('тест')
strio.each_char {|char| chars.push(char) }
chars # => ["т", "е", "с", "т"]
chars = []
strio = StringIO.new('こんにちは')
strio.each_char {|char| chars.push(char) }
chars # => ["こ", "ん", "に", "ち", "は"]
스트림 위치가 중요해요:
chars = []
strio = StringIO.new('こんにちは')
strio.getc # => "こ"
strio.pos # => 3 # 3-byte character was read.
strio.each_char {|char| chars.push(char) }
chars # => ["ん", "に", "ち", "は"]
스트림 끝이면 블록을 호출하지 않아요:
strio.eof? # => true
strio.each_char {|char| fail 'Boo!' }
strio.eof? # => true
블록이 없으면 새 Enumerator를 반환해요.
each_codepoint { |codepoint| ... } → self
블록을 주면 스트림에서 연속되는 각 코드포인트마다 블록을 호출하고, 위치를 스트림 끝으로 설정하고 self를 반환해요.
각 코드포인트는 문자의 정수 값이에요:
codepoints = []
strio = StringIO.new('hello')
strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
strio.eof? # => true
codepoints # => [104, 101, 108, 108, 111]
codepoints = []
strio = StringIO.new('тест')
strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
codepoints # => [1090, 1077, 1089, 1090]
codepoints = []
strio = StringIO.new('こんにちは')
strio.each_codepoint {|codepoint| codepoints.push(codepoint) }
codepoints # => [12371, 12435, 12395, 12385, 12399]
블록이 없으면 새 Enumerator를 반환해요.
each_line(sep = $/, chomp: false) { |line| ... } → self
블록을 주면 스트림의 남은 각 줄마다 블록을 호출하고 self를 반환해요. 스트림 위치는 파일 끝에 남겨요.
인자 없음
인자 없이 호출하면 기본 레코드 구분자(전역 변수 $/, 초기값 "\n")로 줄을 읽어요.
strio = StringIO.new(TEXT)
strio.each_line {|line| p line }
strio.eof? # => true
Output:
"First line\n"
"Second line\n"
"\n"
"Fourth line\n"
"Fifth line\n"
인자 sep
문자열 인자 sep만 주면 그 문자열을 레코드 구분자로 써서 줄을 읽어요:
strio = StringIO.new(TEXT)
strio.each_line(' ') {|line| p line }
Output:
"First "
"line\nSecond "
"line\n\nFourth "
"line\nFifth "
"line\n"
인자 limit
정수 인자 limit만 주면 기본 레코드 구분자로 줄을 읽되, 각 줄의 크기(문자 수)를 주어진 limit으로 제한해요:
strio = StringIO.new(TEXT)
strio.each_line(10) {|line| p line }
Output:
"First line"
"\n"
"Second lin"
"e\n"
"\n"
"Fourth lin"
"e\n"
"Fifth line"
"\n"
인자 sep와 limit
sep와 limit 둘 다 주면 둘 다 적용돼요:
strio = StringIO.new(TEXT)
strio.each_line(' ', 10) {|line| p line }
Output:
"First "
"line\nSecon"
"d "
"line\n\nFour"
"th "
"line\nFifth"
" "
"line\n"
위치
위에서 말했듯 각 예시의 strio는 스트림 시작에 위치해 있어요. 하지만 다른 경우 위치는 어디든 있을 수 있어요:
strio = StringIO.new(TEXT)
strio.pos = 30 # Set stream position to character 30.
strio.each_line {|line| p line }
Output:
" line\n"
"Fifth line\n"
위치가 문자 경계에 있지 않아도 돼요:
s = 'こんにちは' # Five 3-byte characters.
strio = StringIO.new(s)
strio.pos = 3 # At beginning of second character.
strio.each_line {|line| p line }
strio.pos = 4 # At second byte of second character.
strio.each_line {|line| p line }
strio.pos = 5 # At third byte of second character.
strio.each_line {|line| p line }
Output:
"んにちは"
"\x82\x93にちは"
"\x93にちは"
특별한 레코드 구분자
클래스 IO의 일부 메서드처럼, StringIO.each도 두 가지 특별한 레코드 구분자를 다뤄요. ''는 빈 줄로 구분되는 문단으로, nil은 전체를 한 번에 읽어요:
strio = StringIO.new(TEXT)
strio.each_line('') {|line| p line } # Read as paragraphs (separated by blank lines).
Output:
"First line\nSecond line\n\n"
"Fourth line\nFifth line\n"
strio = StringIO.new(TEXT)
strio.each_line(nil) {|line| p line } # "Slurp"; read it all.
Output:
"First line\nSecond line\n\nFourth line\nFifth line\n"
키워드 인자 chomp
chomp 키워드 인자를 true로 주면(기본값은 false), 각 줄에서 끝의 개행(있으면)을 제거해요:
strio = StringIO.new(TEXT)
strio.each_line(chomp: true) {|line| p line }
Output:
"First line"
"Second line"
""
"Fourth line"
"Fifth line"
블록이 없으면 새 Enumerator를 반환해요.
eof? → true or false
self가 스트림 끝에 위치했는지 여부를 반환해요:
strio = StringIO.new('foo')
strio.pos # => 0
strio.eof? # => false
strio.read # => "foo"
strio.pos # => 3
strio.eof? # => true
strio.close_read
strio.eof? # Raises IOError: not opened for reading
external_encoding → encoding or nil
문자열의 인코딩을 나타내는 Encoding 객체를 반환해요:
strio = StringIO.new('foo')
strio.external_encoding # => #<Encoding:UTF-8>
self가 문자열을 갖지 않고 쓰기 모드라면 nil을 반환해요:
strio = StringIO.new(nil, 'w+')
strio.external_encoding # => nil
getbyte → integer or nil
스트림에서 다음 정수 바이트(문자가 아니라)를 읽고 반환해요:
s = 'foo'
s.bytes # => [102, 111, 111]
strio = StringIO.new(s)
strio.getbyte # => 102
strio.getbyte # => 111
strio.getbyte # => 111
스트림 끝이면 nil을 반환해요:
strio.eof? # => true
strio.getbyte # => nil
바이트를 반환하지 문자를 반환하지 않아요:
s = 'Привет'
s.bytes
# => [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
strio = StringIO.new(s)
strio.getbyte # => 208
strio.getbyte # => 159
s = 'こんにちは'
s.bytes
# => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
strio = StringIO.new(s)
strio.getbyte # => 227
strio.getbyte # => 129
getc → character, byte, or nil
스트림에서 다음 문자(경우에 따라 바이트, 아래 참고)를 읽고 반환해요:
strio = StringIO.new('foo')
strio.getc # => "f"
strio.getc # => "o"
strio.getc # => "o"
스트림 끝이면 nil을 반환해요:
strio.eof? # => true
strio.getc # => nil
문자를 반환하지 바이트를 반환하지 않아요:
strio = StringIO.new('Привет')
strio.getc # => "П"
strio.getc # => "р"
strio = StringIO.new('こんにちは')
strio.getc # => "こ"
strio.getc # => "ん"
위 예시들에서 스트림은 문자의 시작에 위치해 있어요. 다른 경우엔 그렇지 않을 수 있어요:
strio = StringIO.new('こんにちは') # Five 3-byte characters.
strio.pos = 3 # => 3 # At beginning of second character; returns character.
strio.getc # => "ん"
strio.pos = 4 # => 4 # At second byte of second character; returns byte.
strio.getc # => "\x82"
strio.pos = 5 # => 5 # At third byte of second character; returns byte.
strio.getc # => "\x93"
gets(sep = $/, chomp: false) → string or nil
스트림에서 줄을 읽고 반환해요. 스트림 끝이면 nil을 반환해요.
부작용:
- 스트림 위치를 읽은 바이트 수만큼 증가시켜요.
- 반환값을 전역 변수
$_에 할당해요.
인자 없이 호출하면 기본 레코드 구분자(전역 변수 $/, 초기값 "\n")로 줄을 읽어요:
strio = StringIO.new(TEXT)
strio.pos # => 0
strio.gets # => "First line\n"
strio.pos # => 11
$_ # => "First line\n"
strio.gets # => "Second line\n"
strio.read # => "\nFourth line\nFifth line\n"
strio.eof? # => true
strio.gets # => nil
strio = StringIO.new('Привет') # Six 2-byte characters
strio.pos # => 0
strio.gets # => "Привет"
strio.pos # => 12
인자 sep: 문자열 인자 sep만 주면 그 문자열을 레코드 구분자로 써서 줄을 읽어요.
strio = StringIO.new(TEXT)
strio.gets(' ') # => "First "
strio.gets(' ') # => "line\nSecond "
strio.gets(' ') # => "line\n\nFourth "
인자 limit: 정수 인자 limit만 주면 기본 레코드 구분자로 줄을 읽되, 각 줄의 크기(문자 수)를 limit으로 제한해요.
strio = StringIO.new(TEXT)
strio.gets(10) # => "First line"
strio.gets(10) # => "\n"
strio.gets(10) # => "Second lin"
strio.gets(10) # => "e\n"
인자 sep와 limit: 둘 다 주면 둘 다 적용돼요.
strio = StringIO.new(TEXT)
strio.gets(' ', 10) # => "First "
strio.gets(' ', 10) # => "line\nSecon"
strio.gets(' ', 10) # => "d "
위치: 위에서 말했듯 gets는 스트림의 다음 줄을 읽고 반환해요. 위치가 어디든 있을 수 있어요:
strio = StringIO.new(TEXT)
strio.pos = 12
strio.gets # => "econd line\n"
위치가 문자 경계에 있지 않아도 돼요:
strio = StringIO.new('Привет') # Six 2-byte characters.
strio.pos = 2 # At beginning of second character.
strio.gets # => "ривет"
strio.pos = 3 # In middle of second character.
strio.gets # => "\x80ивет"
특별한 레코드 구분자: IO 클래스의 일부 메서드처럼 gets도 두 가지 특별한 레코드 구분자를 다뤄요:
strio = StringIO.new(TEXT)
strio.gets('') # Read "paragraph" (up to empty line).
# => "First line\nSecond line\n\n"
strio = StringIO.new(TEXT)
strio.gets(nil) # "Slurp": read all.
# => "First line\nSecond line\n\nFourth line\nFifth line\n"
키워드 인자 chomp: chomp를 true로 주면(기본값 false), 반환된 줄에서 끝의 개행(있으면)을 제거해요.
strio = StringIO.new(TEXT)
strio.gets # => "First line\n"
strio.gets(chomp: true) # => "Second line"
internal_encoding → nil
nil을 반환해요. IO와의 호환용이에요.
lineno → current_line_number
self의 현재 줄 번호를 반환해요. Line Number 참고.
lineno = new_line_number → new_line_number
self의 현재 줄 번호를 주어진 값으로 설정해요. Line Number 참고.
pos → stream_position
현재 위치(바이트)를 반환해요. Position 참고.
pos = new_position → new_position
현재 위치(바이트)를 설정해요. Position 참고.
pread(maxlen, offset) → string
IO#pread 참고.
putc(obj) → obj
IO#putc 참고.
read([length [, outbuf]]) → string, outbuf, or nil
IO#read 참고.
readlines(sep=$/, chomp: false) → array
IO#readlines 참고.
reopen(other, mode = 'r+') → self
주어진 other(문자열 또는 StringIO)와 mode로 스트림을 다시 초기화해요. IO.new 참고:
StringIO.open('foo') do |strio|
p strio.string
strio.reopen('bar')
p strio.string
other_strio = StringIO.new('baz')
strio.reopen(other_strio)
p strio.string
other_strio.close
end
Output:
"foo"
"bar"
"baz"
rewind → 0
현재 위치와 줄 번호를 0으로 설정해요. Position과 Line Number 참고.
seek(offset, whence = SEEK_SET) → 0
주어진 정수 offset(바이트)로 위치를 설정해요. whence는 주어진 상수에 상대적이에요. IO#seek 참고.
set_encoding(ext_enc, [int_enc[, opt]]) → strio
StringIO의 인코딩을 ext_enc으로 지정해요. ext_enc이 nil이면 기본 외부 인코딩을 사용해요. 2번째 인자 int_enc와 선택적 해시 opt 인자는 무시돼요. IO와의 API 호환용이에요.
set_encoding_by_bom → strio or nil
문자열의 BOM(바이트 순서 표시)에 따라 인코딩을 설정해요. BOM이 있으면 self를, 없으면 nil을 반환해요.
size → integer
self의 문자열 크기(바이트)를 반환해요:
StringIO.new('hello').size # => 5 # Five 1-byte characters.
StringIO.new('тест').size # => 8 # Four 2-byte characters.
StringIO.new('こんにちは').size # => 15 # Five 3-byte characters.
string → string
내부 문자열을 반환해요:
StringIO.open('foo') do |strio|
p strio.string
strio.string = 'bar'
p strio.string
end
Output:
"foo"
"bar"
string = other_string → other_string
저장된 문자열을 other_string으로 바꾸고 위치를 0으로 설정한 뒤 other_string을 반환해요:
StringIO.open('foo') do |strio|
p strio.string
strio.string = 'bar'
p strio.string
end
Output:
"foo"
"bar"
sync → true
true를 반환해요. 다른 스트림 클래스와의 호환용으로만 구현됐어요.
truncate(integer) → 0
버퍼 문자열을 최대 integer 바이트로 잘라요. 스트림이 쓰기용으로 열려 있어야 해요.
ungetbyte(byte) → nil
8비트 바이트를 스트림에 다시 밀어 넣어요("unshift"). Byte IO 참고.
ungetc(character) → nil
문자나 정수를 스트림에 다시 밀어 넣어요("unshift"). Character IO 참고.
write(string, ...) → integer
주어진 문자열을 내부 버퍼 문자열에 추가해요. 스트림이 쓰기용으로 열려 있어야 해요. 인자가 문자열이 아니면 to_s로 변환해요. 쓴 바이트 수를 반환해요. IO#write 참고.