SqueakByExample:10.4
파일 접근(file access)를 위해 스트림 사용하기
여러분은 이미 구성요소들의 컬렉션들에 스트림을 시행하는 법을 보셨습니다. 여러분의 하드 디스크에 있는 파일들에, 스트림을 시행하는 것 또한 가능합니다. 스트림은 일단 만들어지면, 파일에 있는 스트림은 컬렉션에 있는 스트림과 매우 유사합니다: 여러분은 읽기, 쓰기 또는 스트림의 위치를 선정하기 위해 동일한 프토콜을 사용하실 수 있을 것입니다. 우리가 지금 볼 내용처럼 파일 스트림을 만드는 여러 가지 다른 방법들이 있습니다.
파일 스트림 만들기
파일 스트림을 만들려면, 클래스 FileStream에 의해 제공된 다음 인스턴스 생성 메서드들 중의 하나를 사용해야만 할 것입니다:
fileNamed: 읽기와 쓰기를 위해 주어진 이름으로 파일을 엽니다. 만약 파일이 이미 존재하면, 그 파일의 이전 컨텐츠는 아마도 수정되었거나 대체되었을 것이지만, 파일은 닫을 때 불완전 형태가 되지 않을 것입니다. 만약 그 이름이(the name) 아무 디렉토리 일부를 갖고 있지 않으면, 파일은 디폴트 디렉토리에서 생성될 것입니다.
newFileNamed: 주어진 이름으로 새로운 파일을 만들고, 그 파일에 쓰기를 위해 열린 스트림을 답변으로 내놓습니다. 만약 파일이 이미 존재한다면, 유저에게 해야할 일을 요청합니다.
forceNewFileNamed: 주어진 이름으로 새로운 파일을 만들고, 그 파일에 쓰기를 위해 열린 스트림을 답변으로 내놓습니다. 만약 파일이 이미 존재한다면, 새로운 파일을 만들기 전에 요청(질문) 없이 그 파일을 지웁니다.
oldFileNamed: 읽기와 쓰기를 위해 주어진 이름으로 파일을 엽니다. 만약 파일이 이미 존재하면, 그 파일의 이전 컨텐츠는 아마도 수정되었거나 대체되었을 것이지만, 파일은 닫을 때 불완전 형태가 되지 않을 것입니다. 만약 그 이름이(the name) 아무 디렉토리 일부를 갖고 있지 않으면, 파일은 디폴트 디렉토리에서 생성될 것입니다.
readOnlyFileNamed: 읽기를 위해 주어진 이름으로 현존하는 파일을 엽니다.
여러분은 파일에서 스트림을 열 때 마다, 그 스트림을 닫아야 만을 한다는 것을 기억하셔야 합니다. 이 닫기는 close 메서드를 사용하여 수행할 수 있습니다.
stream := FileStream forceNewFileNamed: 'test.txt'.
stream
nextPutAll: 'This text is written in a file named ';
print: stream localName.
stream close.
stream := FileStream readOnlyFileNamed: 'test.txt'.
stream contents. ⇒ 'This text is written in a file named ''test.txt'''
stream close.
메서드 localName은 파일 이름의 마지막 요소를 답변으로 내놓습니다.
여러분은 메서드 fullName을 사용하여 전체 경로(the full path name)에 접근할 수 있습니다. 여러분은 곧 파일 스트림을 수동으로 닫는 것은 고통스러우며, 실수를 유발(error-prone)한다는 것을 알아차리실 것입니다. 그 이유가 FileStream이 그 자체의 컨텐츠를 설정하는 블록을 평가한 후에 새로운 스트림을 자동으로 닫기 위해 forceNewFileNamed:do:라고 지칭되는 메시지를 제공하는 근거입니다.
FileStream
forceNewFileNamed: 'test.txt'
do: [:stream |
stream
nextPutAll: 'This text is written in a file named ';
print: stream localName].
string := FileStream
readOnlyFileNamed: 'test.txt'
do: [:stream | stream contents].
string ⇒ 'This text is written in a file named ''test.txt'''
인수로서 블록을 취하는 스트림 생성 메서드는(the stream-creation) 첫 번째로 파일에 스트림을 만들고 그 다음 인수로서 스트림과 함께 블록을 실행한 후 마지막으로 스트림을 닫습니다. 이 메서드들은 블록에 의해 리턴된 것을 리턴하며, 그것은 블록의 마지막 표현식의 값을 말하는 셈이 됩니다. 이것은 파일의 컨텐츠를 얻고, 변수 문자열에 그 컨텐츠를 집어넣기 위한 이전 예시에서 사용되었습니다.
바이너리 스트림(Binary streams)
디폴트로, 만들어진 스트림은 여러분이 문자를 읽고 쓸 것이라는 것을 의미하는 텍스트 기반(text-based)입니다. 만약 여러분의 스트림이 반드시 바이너리가 되어야 한다면 여러분은 자신의 스트림에 메시지 binary를 반드시 발송하셔야 합니다.
여려분의 스트림이 바이너리 모드(binary mode)에 있을 때, 여러분은 0에서255(1byte)까지의 숫자만을 쓰기 할 수 있습니다. 만약 여러분이 한번에 한 개의 숫자 이상을 쓰기 위해 nextPutAll:을 사용하기 원하신다면, 인수로서 ByteArray를 패스해야만 합니다.
FileStream
forceNewFileNamed: 'test.bin'
do: [:stream |
stream
binary;
nextPutAll: #(145 250 139 98) asByteArray].
FileStream
readOnlyFileNamed: 'test.bin'
do: [:stream |
stream binary.
stream size. ⇒ 4
stream next. ⇒ 145
stream upToEnd. ⇒ a ByteArray(250 139 98)
].
여기에 "test.pgm" (포터블 graymap 파일 포맷)으로 작명된 파일에 그림(picture)을 만드는 다른 예시가 있습니다. 여러분은 여러분이 좋아하는 그리기 프로그램(drawing program)으로 이 파일을 열 수 있습니다.
FileStream
forceNewFileNamed: 'test.pgm'
do: [:stream |
stream
nextPutAll: 'P5'; cr;
nextPutAll: '4 4'; cr;
nextPutAll: '255'; cr;
binary;
nextPutAll: #(255 0 255 0) asByteArray;
nextPutAll: #(0 255 0 255) asByteArray;
nextPutAll: #(255 0 255 0) asByteArray;
nextPutAll: #(0 255 0 255) asByteArray
]
이것은 그림 10.12에 보이는 것처럼 4x4 체스판을 만듭니다.