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 .



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow