(본 게시물은 저작권의 문제 발생시 출판사의 요청에 의해 삭제될 수 있습니다.)
IO 객체
루비는 입/출력을 담당하는 기본 클래스 IO를 제공한다. IO객체는 루비프로그램과 외부 리소스 사이의 양방향 채널 역할을 한다. IO객체는 결국 일과 쓰는 것이 전부이다.
파일 열고 닫기
파일 객체는 File.new 메서드를 이용해서 생성할 수 있다.
file = File.new("testfile", "r")
# ... 파일에 대한 처리
file.close
첫 번째 매개변수는 파일이름, 두 번째 인자는 모드 문자열, 읽기 모드, 쓰기 모드, 읽기 쓰기모드로 File 객체 생성이 가능하다. (읽기 쓰기모드는 r+, 쓰기모드는 w, 읽기 모드 r)
File.open 메서드는 파일을 여는 데 사용한다. 일반적으로 File.open 메서드는 File.new 처럼 사용할 수 있다. File.open에 블록을 함께 사용하면 이야기가 달라진다. File.new 처럼 새로운 File 객체를 반환하는 대신, 새로 열린 파일 객체를 매개 변수로 블록을 실행해 준다. 그리고 블록 실행이 끝나면 파일도 자동으로 닫는다.
File.open("testfile", "r") do | file |
# ... 파일에 대한 처리
end # <= 파일은 여기서 자동으로 닫힌다.
앞선 예제에서는 예외 발생시 file.close가 호출 되지 않지만 File.open을 블록과 함께 사용하면 예외가 블록에서 발생하더라도 예외가 호출자(caller)에게 전달되기 전에 파일을 닫아준다.
class File
def File.open(*args)
result = f = File.new(*args)
if block_given?
begin
result = yield f
ensure
f.close
end
end
result
end
end
파일 읽고 쓰기
파일 객체도 기본적인 I/O 메서드를 모두 사용할 수 있다. gets 메서드가 표준 입력에서 한줄을 읽는 것처럼 file.gets 는 file 객체에서 한 줄을 읽는다.
while line = gets
put line
end
위 프로그램을 아무인자없이 실행하면 콘솔에서 한 줄을 읽어 콘솔로 복제하여 출력한다. 명령행에서 하나이상의 파일명을 적어주면 gets 메서드는 파일들을 차례로 한 줄씩 읽어온다.
아래의 예제는 파일을 명시적으로 열어서 읽어온다.
File.open("testfile") do | file |
while line = file.gets
puts line
end
end
읽기를 위한 반복자
IO#each_byte 메서드는 IO객체로부터 8비트(1바이트)씩 읽어서 블록을 실행한다. chr 메서드는 정수를 받아서 해당하는 아스키 문자열을 반환한다.
File.open("testfile") do | file |
file.each_byte.with_index do | ch, index |
print "#{ch.chr}:#{ch} "
break if index > 10
end
end
실행결과
T:84 h:104 i:105 s:115 :32 i:105 ..
IO#each_line 메서드는 파일로부터 한 줄씩 읽어서 블록을 호출한다. 다음 예제는 String#dump 메서드를 이용해 출력을 한다.
File.open("testfile") do | file |
file.each_line { | line | puts "Got #{line.dump} " }
end
실행 결과
Got "This is line one\n"
Got "This is line two\n"
..
each_line 메서드에는 행 구분자로 어떤 문자 시퀀스든 넘겨줄 수 있다. 다음 예제에서는 라인 분리자로 "e"를 사용한다.
File.open("testfile") do | file |
file.each_line("e") { | line | puts "Got #{ line.dump }" }
end
실행 결과
Got "This is line"
Got " one"
Got "\nThis is line"
Got " two\nThis is line"
Got " thre"
Got "e"
Got "\nAnd so on.. \n"
문자열로 읽거나 줄별로 나뉜 배열의 형태로 읽어올 수 있다.
# 문자열로 읽기
str = IO.read("testfile")
str.length # => 66
str[0, 30] # => "This is line one\n This is line"
# 배열로 읽기
arr = IO.readlines
arr.length # => 4
arr[0] # => "This is line one\n"
문자열로 I/O 하기
하나 이상의 파일로 읽기 쓰기를 하는 경우, 데이터가 파일에 있지 않은 경우를 가정해보자. StringIO를 사용하자. 이 객체는 다른 I/O객체 처럼 행동한다. 하지만 파일이 아니라 문자열로부터 읽고 문자열에 쓴다는 차이점이 있다. StringIO 객체를 읽기용으로 사용하려면 문자열을 제공해야 한다.
require 'stringio'
ip = StringIO.new("now is\nthe time \nto lean\nRuby!")
op = StringIO.new("", "w")
ip.each_line do | line |
op.puts line.reverse
end
op.string # => "\nsi won\nnemit eht\n nnrael ot\n!yubR\n"
끄읕.