サーチ…


構文

  • (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-STREAMGET-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

OPENCLOSEを使用して手動で行うこともできます。

(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)))

同じことはOPENCLOSE使って手動で行うことができます。

(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-bytewrite-byteread-charを処理するread-charwrite-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-sequencewrite-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-sequencewrite-string置き換えることができwrite-string



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow