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 .



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow