WITH-OPEN-FILE — 파일을 열고 자동으로 닫는 매크로
WITH-OPEN-FILE — 파일을 열고 자동으로 닫는 매크로
파일을 열어 그 스트림으로 작업하고, 끝나면 (정상이든 비정상이든) 자동으로 닫아주는 표준 파일 처리 매크로예요. 파일을 직접 open/close로 관리하지 않아도 되는 편리함을 줘요.
시그니처
with-open-file (stream filespec {options}*) declaration* form* => results*
본문
인자와 값 (Arguments and Values)
stream— 변수.filespec— 경로명 지정자(pathname designator).options— 폼들; 평가돼요.declaration—declare식; 평가되지 않아요.forms— 암묵적 progn.results—forms가 돌려준 값.
설명 (Description)
with-open-file은 open을 써서 filespec이 이름 짓는 파일에 대한 파일 스트림(file stream)을 만들어요. filespec은 열 파일의 이름이고, options는 open의 키워드 인자로 쓰여요.
stream 변수가 바인딩되는 스트림 객체는 동적 지속 기간(dynamic extent)을 가지며, 그 기간은 폼에서 나가면 끝나요.
with-open-file은 stream을 open이 돌려준 값에 바인딩하고 forms를 암묵적 progn으로 평가해요.
throw 사용처럼 제어가 본문을 정상적으로든 비정상적으로든 떠나면 파일은 자동으로 닫혀요. 새 출력 파일을 쓰는 중에 제어가 비정상적으로 떠나면 파일은 중단(abort)되고, 가능한 한 파일이 처음부터 열린 적 없던 것처럼 파일 시스템이 남아요.
:if-exists nil이나 :if-does-not-exist nil을 쓰면 stream이 nil에 바인딩될 수 있어요. :if-does-not-exist nil을 쓴다면 유효한 스트림인지 확인해야 해요.
stream 변수를 할당(assign)하려고 하면 결과는 정의되지 않아요(undefined). 컴파일러는 그런 시도를 발견하면 경고를 내보낼 수 있어요.
예제 (Examples)
(setq p (merge-pathnames "test"))
=> #<PATHNAME :HOST NIL :DEVICE device-name :DIRECTORY directory-name
:NAME "test" :TYPE NIL :VERSION :NEWEST>
(with-open-file (s p :direction :output :if-exists :supersede)
(format s "Here are a couple~%of test data lines~%")) => NIL
(with-open-file (s p)
(do ((l (read-line s) (read-line s nil 'eof)))
((eq l 'eof) "Reached end of file.")
(format t "~&*** ~A~%" l)))
>> *** Here are a couple
>> *** of test data lines
=> "Reached end of file."
;; Normally one would not do this intentionally because it is
;; not perspicuous, but beware when using :IF-DOES-NOT-EXIST NIL
;; that this doesn't happen to you accidentally...
(with-open-file (foo "no-such-file" :if-does-not-exist nil)
(read foo))
>> hello?
=> HELLO? ;This value was read from the terminal, not a file!
;; Here's another bug to avoid...
(with-open-file (foo "no-such-file" :direction :output :if-does-not-exist nil)
(format foo "Hello"))
=> "Hello" ;FORMAT got an argument of NIL!
두 번째 칸의 예제들은 :if-does-not-exist nil로 foo가 nil에 바인딩된 상태에서 읽기/쓰기를 시도해 생기는 함정들을 보여줘요. 파일이 열리지 않았더라도 (read foo)는 터미널에서 값을 읽어버리고, (format foo ...)는 nil을 인자로 받아 들아 최종값을 돌려주죠.
부수 효과 (Side Effects)
진입 시 filename이 이름 짓는 파일에 대한 스트림을 만들고, 종료 시 스트림을 닫아요. 어떤 구현에서는 파일이 열려 있는 동안 잠길(lock) 수도 있어요. 스트림이 출력 스트림이면 파일이 만들어질 수 있어요.
영향 (Affected By)
호스트 컴퓨터의 파일 시스템.
특이 상황 (Exceptional Situations)
open 함수 참고.
참고 (Notes)
없음.
더 알아보기
open— 파일 스트림을 여는 함수close— 스트림을 닫는 함수pathname,logical-pathname— 경로명 다루기