common-lisp
I flussi
Ricerca…
Sintassi
-
(read-char &optional stream eof-error-p eof-value recursive-p)
=> carattere -
(write-char character &optional stream)
=> carattere -
(read-line &optional stream eof-error-p eof-value recursive-p)
=> riga, missing-newline-p -
(write-line line &optional stream)
=> linea
Parametri
Parametro | Dettaglio |
---|---|
stream | Lo stream da cui leggere o scrivere. |
eof-error-p | Dovrebbe essere segnalato un errore se si incontra la fine del file. |
eof-value | Quale valore deve essere restituito se eof è incontrato, e eof-error-p è falso. |
recursive-p | L'operazione di lettura viene chiamata in modo ricorsivo da READ . Di solito questo dovrebbe essere lasciato come NIL . |
character | Il personaggio da scrivere o il personaggio letto. |
line | La riga da scrivere o la riga che è stata letta. |
Creazione di flussi di input da stringhe
La macro WITH-INPUT-FROM-STRING
può essere utilizzata per creare uno stream da una stringa.
(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
Lo stesso può essere fatto manualmente usando 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)))
Scrivere l'output su una stringa
La macro WITH-OUTPUT-TO-STRING
può essere utilizzata per creare un flusso di output stringa e restituire la stringa risultante alla fine.
(with-output-to-string (str)
(write-line "Foobar!" str)
(write-string "Barfoo!" str))
;=> "Foobar!
; Barfoo!"
Lo stesso può essere fatto manualmente usando MAKE-STRING-OUTPUT-STREAM
e GET-OUTPUT-STREAM-STRING
.
(let ((str (make-string-output-stream)))
(write-line "Foobar!" str)
(write-string "Barfoo!" str)
(get-output-stream-string str))
Flussi grigi
I flussi grigi sono un'estensione non standard che consente flussi definiti dall'utente. Fornisce classi e metodi che l'utente può estendere. Dovresti controllare il manuale delle implementazioni per vedere se fornisce stream grigi.
Per un semplice esempio, un flusso di input di caratteri che restituisce caratteri casuali potrebbe essere implementato in questo modo:
(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
Lettura del file
Un file può essere aperto per la lettura come uno stream utilizzando la macro 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
Lo stesso può essere fatto manualmente usando OPEN
e CLOSE
.
(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)))
Nota che READ-LINE
crea una nuova stringa per ogni riga. Questo può essere lento. Alcune implementazioni forniscono una variante, che può leggere una riga in un buffer di stringa. Esempio: READ-LINE-INTO
per Allegro CL.
Scrivere su un file
Un file può essere aperto per la scrittura come uno stream utilizzando la macro 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)))
Lo stesso può essere fatto manualmente con OPEN
e 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))
Copia di un file
Copia byte per byte di un file
La seguente funzione copia un file in un altro eseguendo una copia esatta byte per byte, ignorando il tipo di contenuto (che può essere una linea di caratteri in alcuni dati di codifica o binari):
(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))))))
Il tipo (unsigned-byte 8)
è il tipo di byte a 8 bit. Le funzioni read-byte
e write-byte
funzionano su byte, invece di read-char
e write-char
che funzionano sui caratteri. read-byte
restituisce un byte letto dallo stream o NIL
alla fine del file se il secondo parametro opzionale è NIL
(altrimenti segnala un errore).
Copia di massa
Una copia esatta, più efficiente della precedente. può essere fatto leggendo e scrivendo i file con grandi blocchi di dati ogni volta, invece di singoli byte:
(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
sono qui usate con un buffer che è un vettore di byte (possono operare su sequenze di byte o caratteri). read-sequence
riempie l'array con i byte letti ogni volta e restituisce il numero di byte letti (che può essere inferiore alla dimensione dell'array quando viene raggiunta la fine del file). Si noti che la matrice viene modificata in modo distruttivo ad ogni iterazione.
Copia esatta riga per riga di un file
L'ultimo esempio è una copia eseguita leggendo ogni riga di caratteri del file di input e scrivendola nel file di output. Nota che, poiché vogliamo una copia esatta, dobbiamo controllare se l'ultima riga del file di input è terminata o meno da un carattere di fine riga. Per questo motivo, utilizziamo i due valori restituiti da read-line
: una nuova stringa contenente i caratteri della riga successiva e un valore booleano che è true se la riga è l'ultimo del file e non contiene il carattere di fine riga finale (S). In questo caso viene utilizzata la write-string
di write-line
anziché la write-line
di write-line
, poiché la prima non aggiunge una nuova riga alla fine della riga.
(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)))))))))
Si noti che questo programma è indipendente dalla piattaforma, dal momento che i caratteri di nuova riga (che variano in diversi sistemi operativi) vengono automaticamente gestiti dalle funzioni read-line
e write-line
.
Lettura e scrittura di interi file da e verso le stringhe
La seguente funzione legge un intero file in una nuova stringa e lo restituisce:
(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))))
Il risultato è NIL
se il file non esiste.
La seguente funzione scrive una stringa in un file. Un parametro parola chiave viene utilizzato per specificare cosa fare se il file esiste già (per impostazione predefinita causa un errore, i valori ammissibili sono quelli della macro con 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)))
In questo caso write-sequence
può essere sostituita con write-string
.