Zoeken…


Syntaxis

  • (read-char &optional stream eof-error-p eof-value recursive-p) => karakter
  • (write-char character &optional stream) => karakter
  • (read-line &optional stream eof-error-p eof-value recursive-p) => line, missing-newline-p
  • (write-line line &optional stream) => regel

parameters

Parameter Detail
stream De stream om van te lezen of naar te schrijven.
eof-error-p Moet er een fout worden gemeld als het einde van het bestand wordt aangetroffen.
eof-value Welke waarde moet worden geretourneerd als eof wordt aangetroffen en eof-error-p false is.
recursive-p Wordt de leesbewerking recursief aangeroepen vanuit READ . Meestal moet dit als NIL worden gelaten.
character Het te schrijven karakter of het gelezen karakter.
line De te schrijven regel of de gelezen regel.

Inputstromen van strings maken

De macro WITH-INPUT-FROM-STRING kan worden gebruikt om een stream van een string te maken.

(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

Hetzelfde kan handmatig worden gedaan met 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)))

Uitvoer naar een string schrijven

De macro WITH-OUTPUT-TO-STRING kan worden gebruikt om een stringuitvoerstroom te maken en de resulterende string aan het einde te retourneren.

(with-output-to-string (str)
  (write-line "Foobar!" str)
  (write-string "Barfoo!" str))
;=> "Foobar!
;   Barfoo!"

Hetzelfde kan handmatig worden gedaan met MAKE-STRING-OUTPUT-STREAM en GET-OUTPUT-STREAM-STRING .

(let ((str (make-string-output-stream)))
  (write-line "Foobar!" str)
  (write-string "Barfoo!" str)
  (get-output-stream-string str))

Grijze beken

Grijze streams zijn een niet-standaard extensie waarmee door de gebruiker gedefinieerde streams mogelijk zijn. Het biedt klassen en methoden die de gebruiker kan uitbreiden. Raadpleeg uw implementatiehandleiding om te zien of deze grijze streams biedt.

Voor een eenvoudig voorbeeld kan een tekeninvoerstroom die willekeurige tekens retourneert, als volgt worden geïmplementeerd:

(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

Bestand lezen

Een bestand kan worden geopend om te worden gelezen als een stream met de 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

Hetzelfde kan handmatig worden gedaan met OPEN en 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)))

Merk op dat READ-LINE een nieuwe string maakt voor elke regel. Dit kan langzaam zijn. Sommige implementaties bieden een variant, die een regel in een stringbuffer kan lezen. Voorbeeld: READ-LINE-INTO voor Allegro CL.

Naar een bestand schrijven

Een bestand kan worden geopend voor schrijven als een stream met de 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)))

Hetzelfde kan handmatig worden gedaan met OPEN en 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))

Een bestand kopiëren

Byte per byte van een bestand kopiëren

De volgende functie kopieert een bestand naar een ander door een exacte byte-per-byte-kopie uit te voeren, waarbij het soort inhoud wordt genegeerd (dit kunnen regels met tekens zijn in sommige coderings- of binaire gegevens):

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

Het type (unsigned-byte 8) is het type 8-bit bytes. De functies read-byte en write-byte werken op bytes, in plaats van read-char en write-char die op tekens werken. read-byte retourneert een byte gelezen uit de stream of NIL aan het einde van het bestand als de tweede optionele parameter NIL (anders geeft dit een fout aan).

Bulk exemplaar

Een exacte kopie, efficiënter dan de vorige. kan worden gedaan door de bestanden met grote hoeveelheden gegevens elke keer te lezen en te schrijven in plaats van enkele bytes:

(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 en write-sequence worden hier gebruikt met een buffer die een vector van bytes is (ze kunnen werken op sequenties van bytes of tekens). read-sequence vult de array elke keer met de gelezen bytes en retourneert het aantal gelezen bytes (dat kan kleiner zijn dan de grootte van de array wanneer het einde van het bestand is bereikt). Merk op dat de array bij elke iteratie destructief wordt gewijzigd.

Exacte kopie regel per regel van een bestand

Het laatste voorbeeld is een kopie die wordt uitgevoerd door elke regel tekens van het invoerbestand te lezen en naar het uitvoerbestand te schrijven. Omdat we een exacte kopie willen, moeten we controleren of de laatste regel van het invoerbestand wordt beëindigd of niet door een teken aan het einde van de regel. Om deze reden gebruiken we de twee waarden die worden geretourneerd door read-line : een nieuwe tekenreeks met de tekens van de volgende regel, en een booleaanse waarde die waar is als de regel de laatste van het bestand is en niet het laatste teken voor de nieuwe regel bevat (s). In dit geval wordt een write-string gebruikt in plaats van een write-line , aangezien de eerste geen nieuwe regel toevoegt aan het einde van de regel.

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

Merk op dat dit programma platformonafhankelijk is, aangezien de tekens voor de nieuwe regel (variërend in verschillende besturingssystemen) automatisch worden beheerd door de functies read-line en write-line .

Volledige bestanden lezen en schrijven van en naar tekenreeksen

De volgende functie leest een heel bestand in een nieuwe string en geeft het terug:

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

Het resultaat is NIL als het bestand niet bestaat.

De volgende functie schrijft een tekenreeks naar een bestand. Een trefwoordparameter wordt gebruikt om op te geven wat te doen als het bestand al bestaat (standaard veroorzaakt het een fout, de toelaatbare waarden zijn die van de 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)))

In dit geval kan de write-sequence worden vervangen door de write-string .



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow