common-lisp
ストリーム
サーチ…
構文
-
(read-char &optional stream eof-error-p eof-value recursive-p)
=>文字 -
(write-char character &optional stream)
=>文字 -
(read-line &optional stream eof-error-p eof-value recursive-p)
=>行、欠落改行-p -
(write-line line &optional stream)
=>行
パラメーター
パラメータ | 詳細 |
---|---|
stream | 読み書きするストリーム。 |
eof-error-p | ファイルの終わりに遭遇した場合にエラーが通知されるべきかどうか。 |
eof-value | eofに遭遇し、 eof-error-p がfalseの場合、返される値はどれですか。 |
recursive-p | 読み取り操作はREAD から再帰的に呼び出されますか?通常これはNIL ままにしてNIL ます。 |
character | 書き込む文字、または読み込んだ文字。 |
line | 書き込む行、または読み込んだ行。 |
文字列から入力ストリームを作成する
WITH-INPUT-FROM-STRING
マクロを使用すると、文字列からストリームを作成できます。
(with-input-from-string (str "Foobar")
(loop for i from 0
for char = (read-char str nil nil)
while char
do (format t "~d: ~a~%" i char)))
; 0: F
; 1: o
; 2: o
; 3: b
; 4: a
; 5: r
;=> NIL
MAKE-STRING-INPUT-STREAM
を使用して手動で行うこともできます。
(let ((str (make-string-input-stream "Foobar")))
(loop for i from 0
for char = (read-char str nil nil)
while char
do (format t "~d: ~a~%" i char)))
文字列への出力の書き込み
WITH-OUTPUT-TO-STRING
マクロを使用して、文字列出力ストリームを作成し、最後に結果の文字列を返すことができます。
(with-output-to-string (str)
(write-line "Foobar!" str)
(write-string "Barfoo!" str))
;=> "Foobar!
; Barfoo!"
MAKE-STRING-OUTPUT-STREAM
とGET-OUTPUT-STREAM-STRING
を使用して手動で行うこともできます。
(let ((str (make-string-output-stream)))
(write-line "Foobar!" str)
(write-string "Barfoo!" str)
(get-output-stream-string str))
グレイストリーム
グレーストリームは、ユーザーが定義したストリームを許可する非標準の拡張です。ユーザーが拡張できるクラスとメソッドを提供します。グレーストリームを提供するかどうかについては、実装マニュアルを参照してください。
簡単な例として、ランダムな文字を返す文字入力ストリームは次のように実装できます:
(defclass random-character-input-stream (fundamental-character-input-stream)
((character-table
:initarg :character-table
:initform "abcdefghijklmnopqrstuvwxyz
" ; The newline is necessary.
:accessor character-table))
(:documentation "A stream of random characters."))
(defmethod stream-read-char ((stream random-character-input-stream))
(let ((table (character-table stream)))
(aref table (random (length table)))))
(let ((stream (make-instance 'random-character-input-stream)))
(dotimes (i 5)
(print (read-line stream))))
; "gyaexyfjsqdcpciaaftoytsygdeycrrzwivwcfb"
; "gctnoxpajovjqjbkiqykdflbhfspmexjaaggonhydhayvknwpdydyiabithpt"
; "nvfxwzczfalosaqw"
; "sxeiejcovrtesbpmoppfvvjfvx"
; "hjplqgstbodbalnmxhsvxdox"
;=> NIL
ファイルを読む
WITH-OPEN-FILE
マクロを使用してストリームとして読み込むためのファイルを開くことができます。
(with-open-file (file #P"test.file")
(loop for i from 0
for line = (read-line file nil nil)
while line
do (format t "~d: ~a~%" i line)))
; 0: Foobar
; 1: Barfoo
; 2: Quuxbar
; 3: Barquux
; 4: Quuxfoo
; 5: Fooquux
;=> T
(let ((file (open #P"test.file"))
(aborted t))
(unwind-protect
(progn
(loop for i from 0
for line = (read-line file nil nil)
while line
do (format t "~d: ~a~%" i line))
(setf aborted nil))
(close file :abort aborted)))
READ-LINE
は各行に新しい文字列を作成することに注意してください。これは遅くなることがあります。いくつかの実装では、行を文字列バッファに読み込むことができるバリアントが提供されています。例:Allegro CLのREAD-LINE-INTO
ファイルへの書き込み
ファイルはWITH-OPEN-FILE
マクロを使用してストリームとして書き込むために開くことができます。
(with-open-file (file #P"test.file" :direction :output
:if-exists :append
:if-does-not-exist :create)
(dolist (line '("Foobar" "Barfoo" "Quuxbar"
"Barquux" "Quuxfoo" "Fooquux"))
(write-line line file)))
同じことはOPEN
とCLOSE
使って手動で行うことができます。
(let ((file (open #P"test.file" :direction :output
:if-exists :append
:if-does-not-exist :create)))
(dolist (line '("Foobar" "Barfoo" "Quuxbar"
"Barquux" "Quuxfoo" "Fooquux"))
(write-line line file))
(close file))
ファイルのコピー
ファイルのバイト単位でのコピー
次の関数は、正確なバイト/バイトコピーを実行し、コンテンツの種類(エンコーディングまたはバイナリデータの文字列のいずれか)を無視して、ファイルを別のファイルにコピーします。
(defun byte-copy (infile outfile)
(with-open-file (instream infile :direction :input :element-type '(unsigned-byte 8)
:if-does-not-exist nil)
(when instream
(with-open-file (outstream outfile :direction :output :element-type '(unsigned-byte 8)
:if-exists :supersede)
(loop for byte = (read-byte instream nil)
while byte
do (write-byte byte outstream))))))
タイプ(unsigned-byte 8)
は、8ビットのバイトのタイプです。関数read-byte
とwrite-byte
、 read-char
を処理するread-char
とwrite-char
代わりに、 write-byte
動作します。 read-byte
は、ストリームから読み取られたread-byte
返します。第2のオプションのパラメータがNIL
場合は、ファイルの最後にNIL
を返します(それ以外の場合は、エラーを通知します)。
バルクコピー
正確なコピー、より効率的な前のもの。 1バイトではなく、大量のデータを読み込んだり書き込んだりすることができます。
(defun bulk-copy (infile outfile)
(with-open-file (instream infile :direction :input :element-type '(unsigned-byte 8)
:if-does-not-exist nil)
(when instream
(with-open-file (outstream outfile :direction :output :element-type '(unsigned-byte 8)
:if-exists :supersede)
(let ((buffer (make-array 8192 :element-type '(unsigned-byte 8))))
(loop for bytes-read = (read-sequence buffer instream)
while (plusp bytes-read)
do (write-sequence buffer outstream :end bytes-read)))))))
read-sequence
とwrite-sequence
は、ここではバイトのベクトルであるバッファで使用されます(バイトまたは文字のシーケンスで動作できます)。 read-sequence
は、毎回読み込まれたバイトでread-sequence
塗りつぶし、読み取られたバイト数を返します(ファイルの終わりに達したときに配列のサイズよりも小さくなります)。配列は各繰り返しで破壊的に変更されることに注意してください。
ファイルの1行あたりの正確なコピー行
最後の例は、入力ファイルの各行を読み取り、出力ファイルに書き込むことによって実行されるコピーです。正確なコピーが必要なので、入力ファイルの最後の行が行末の文字で終了するかどうかをチェックする必要があります。この理由から、 read-line
によって返される2つの値、すなわち次の行の文字を含む新しい文字列と、その行がファイルの最後であり、最後の改行文字を含まない場合に真 (s)。この場合、 write-line
代わりにwrite-string
が使用されwrite-string
は、前者が行末に改行を追加しないためです。
(defun line-copy (infile outfile)
(with-open-file (instream infile :direction :input :if-does-not-exist nil)
(when instream
(with-open-file (outstream outfile :direction :output :if-exists :supersede)
(let (line missing-newline-p)
(loop
(multiple-value-setq (line missing-newline-p)
(read-line instream nil nil))
(cond (missing-newline-p ; we are at the end of file
(when line (write-string line outstream)) ; note `write-string`
(return)) ; exit from simple loop
(t (write-line line outstream)))))))))
このプログラムはプラットフォームに依存しないことに注意してください。改行文字(オペレーティングシステムによって異なる)は、 read-line
およびwrite-line
関数によって自動的に管理されるからです。
文字列とのファイル全体の読み書き
次の関数は、ファイル全体を新しい文字列に読み込んで返します。
(defun read-file (infile)
(with-open-file (instream infile :direction :input :if-does-not-exist nil)
(when instream
(let ((string (make-string (file-length instream))))
(read-sequence string instream)
string))))
ファイルが存在しない場合、結果はNIL
なります。
次の関数は文字列をファイルに書き込みます。キーワード・パラメータは、ファイルがすでに存在する場合に何をするかを指定するために使用されます(デフォルトではエラーが発生し、許容値はwith-open-file
マクロの値with-open-file
)。
(defun write-file (string outfile &key (action-if-exists :error))
(check-type action-if-exists (member nil :error :new-version :rename :rename-and-delete
:overwrite :append :supersede))
(with-open-file (outstream outfile :direction :output :if-exists action-if-exists)
(write-sequence string outstream)))
この場合、 write-sequence
はwrite-string
置き換えることができwrite-string
。