common-lisp
Ruisseaux
Recherche…
Syntaxe
-
(read-char &optional stream eof-error-p eof-value recursive-p)
=> caractère -
(write-char character &optional stream)
=> caractère -
(read-line &optional stream eof-error-p eof-value recursive-p)
=> ligne manquante-newline-p -
(write-line line &optional stream)
=> ligne
Paramètres
Paramètre | Détail |
---|---|
stream | Le flux à lire ou à écrire. |
eof-error-p | Si une erreur est signalée si la fin du fichier est rencontrée. |
eof-value | Quelle valeur doit être renvoyée si eof est rencontré, et eof-error-p est faux. |
recursive-p | La lecture-opération est-elle appelée de manière récursive à partir de READ . Habituellement, cela devrait être laissé comme NIL . |
character | Le caractère à écrire ou le caractère lu. |
line | La ligne à écrire ou la ligne qui a été lue. |
Créer des flux d'entrée à partir de chaînes
La macro WITH-INPUT-FROM-STRING
peut être utilisée pour créer un flux à partir d'une chaîne.
(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
La même chose peut être faite manuellement en utilisant 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)))
Ecrire un résultat dans une chaîne
La macro WITH-OUTPUT-TO-STRING
peut être utilisée pour créer un flux de sortie de chaîne et renvoyer la chaîne résultante à la fin.
(with-output-to-string (str)
(write-line "Foobar!" str)
(write-string "Barfoo!" str))
;=> "Foobar!
; Barfoo!"
La même chose peut être faite manuellement en utilisant MAKE-STRING-OUTPUT-STREAM
et GET-OUTPUT-STREAM-STRING
.
(let ((str (make-string-output-stream)))
(write-line "Foobar!" str)
(write-string "Barfoo!" str)
(get-output-stream-string str))
Ruisseaux gris
Les flux gris sont une extension non standard qui autorise les flux définis par l'utilisateur. Il fournit des classes et des méthodes que l'utilisateur peut étendre. Vous devriez vérifier votre manuel d'implémentation pour voir s'il fournit des flux de gris.
Pour un exemple simple, un flux de saisie de caractères qui renvoie des caractères aléatoires pourrait être implémenté comme ceci:
(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
Fichier de lecture
Un fichier peut être ouvert pour la lecture en tant que flux en utilisant 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
La même chose peut être faite manuellement en utilisant OPEN
et 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)))
Notez que READ-LINE
crée une nouvelle chaîne pour chaque ligne. Cela peut être lent. Certaines implémentations fournissent une variante qui peut lire une ligne dans un tampon de chaîne. Exemple: READ-LINE-INTO
pour Allegro CL.
Ecrire dans un fichier
Un fichier peut être ouvert pour l'écriture en tant que flux à l'aide de 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)))
La même chose peut être faite manuellement avec OPEN
et 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))
Copier un fichier
Copier byte-by-byte d'un fichier
La fonction suivante copie un fichier dans un autre en effectuant une copie exacte octet par octet, en ignorant le type de contenu (qui peut être soit des lignes de caractères dans certaines données d'encodage ou binaires):
(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))))))
Le type (unsigned-byte 8)
est le type d'octets de 8 bits. Les fonctions read-byte
et write-byte
fonctionnent sur des octets, au lieu de read-char
et write-char
qui fonctionnent sur les caractères. read-byte
renvoie un octet lu dans le flux ou NIL
à la fin du fichier si le deuxième paramètre facultatif est NIL
(sinon, il signale une erreur).
Copie en vrac
Une copie exacte, plus efficace que la précédente. peut être fait en lisant et en écrivant les fichiers avec de gros blocs de données à chaque fois, au lieu d’octets uniques:
(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
et write-sequence
sont utilisés ici avec un tampon qui est un vecteur d'octets (ils peuvent fonctionner sur des séquences d'octets ou de caractères). read-sequence
remplit le tableau avec les octets lus à chaque fois et renvoie le nombre d'octets lus (qui peut être inférieur à la taille du tableau lorsque la fin du fichier est atteinte). Notez que le tableau est modifié de manière destructive à chaque itération.
Copie exacte ligne par ligne d'un fichier
Le dernier exemple est une copie effectuée en lisant chaque ligne de caractères du fichier d'entrée et en l'écrivant dans le fichier de sortie. Notez que, comme nous voulons une copie exacte, nous devons vérifier si la dernière ligne du fichier d'entrée est terminée ou non par un caractère de fin de ligne. Pour cette raison, nous utilisons les deux valeurs renvoyées par read-line
: une nouvelle chaîne contenant les caractères de la ligne suivante et une valeur booléenne qui est vraie si la ligne est la dernière du fichier et ne contient pas le caractère de nouvelle ligne final (s). Dans ce cas, write-string
est utilisé à la place de write-line
, car le premier n'ajoute pas de nouvelle ligne à la fin de la ligne.
(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)))))))))
Notez que ce programme est indépendant de la plate-forme, car le ou les caractères de la nouvelle ligne (variant selon les systèmes d'exploitation) sont automatiquement gérés par les fonctions read-line
et d' write-line
.
Lecture et écriture de fichiers entiers vers et depuis des chaînes
La fonction suivante lit un fichier entier dans une nouvelle chaîne et la renvoie:
(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))))
Le résultat est NIL
si le fichier n'existe pas.
La fonction suivante écrit une chaîne dans un fichier. Un paramètre de mot-clé est utilisé pour spécifier quoi faire si le fichier existe déjà (par défaut, il provoque une erreur, les valeurs admissibles sont celles de la macro 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)))
Dans ce cas, la write-sequence
peut être remplacée par une write-string
d' write-string
.