Suche…


Syntax

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

Parameter

Parameter Detail
stream Der Stream, aus dem gelesen oder geschrieben werden soll.
eof-error-p Sollte ein Fehler gemeldet werden, wenn das Dateiende aufgetreten ist.
eof-value Welcher Wert sollte zurückgegeben werden, wenn eof gefunden wird und eof-error-p falsch ist.
recursive-p Wird die Leseoperation rekursiv von READ aufgerufen. Normalerweise sollte dies als NIL belassen werden.
character Das zu schreibende Zeichen oder das gelesene Zeichen.
line Die zu schreibende Zeile oder die gelesene Zeile.

Eingabeströme aus Strings erstellen

Das Makro WITH-INPUT-FROM-STRING kann verwendet werden, um aus einem String einen Stream zu erstellen.

(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

Dasselbe kann manuell mit 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)))

Ausgabe in einen String schreiben

Das Makro WITH-OUTPUT-TO-STRING kann verwendet werden, um einen String-Ausgabestrom zu erstellen und den resultierenden String am Ende zurückzugeben.

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

Dasselbe kann manuell mit MAKE-STRING-OUTPUT-STREAM und GET-OUTPUT-STREAM-STRING .

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

Graue Bäche

Gray-Streams sind eine nicht standardmäßige Erweiterung, die benutzerdefinierte Streams ermöglicht. Es bietet Klassen und Methoden, die der Benutzer erweitern kann. Sie sollten in Ihrem Implementierungshandbuch nachsehen, ob Gray-Streams verfügbar sind.

Für ein einfaches Beispiel könnte ein Zeicheneingabestrom, der zufällige Zeichen zurückgibt, folgendermaßen implementiert werden:

(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

Datei lesen

Eine Datei kann mit dem Makro WITH-OPEN-FILE als Stream zum Lesen geöffnet werden.

(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

Dasselbe kann manuell mit OPEN und 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)))

Beachten Sie, dass READ-LINE für jede Zeile eine neue Zeichenfolge erstellt. Das kann langsam sein. Einige Implementierungen stellen eine Variante bereit, die eine Zeile in einen Zeichenkettenpuffer lesen kann. Beispiel: READ-LINE-INTO für Allegro CL.

In eine Datei schreiben

Eine Datei kann zum Schreiben als Stream mit dem Makro WITH-OPEN-FILE geöffnet werden.

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

Dasselbe kann manuell mit OPEN und 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))

Datei kopieren

Kopieren Sie Byte für Byte einer Datei

Die folgende Funktion kopiert eine Datei in eine andere, indem sie eine genaue Byte-pro-Byte-Kopie durchführt und dabei die Art des Inhalts ignoriert (dies können entweder Zeilen von Zeichen in einer Codierung oder binäre Daten sein):

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

Der Typ (unsigned-byte 8) ist der Typ von 8-Bit-Bytes. Die Funktionen read-byte und write-byte arbeiten mit Bytes, anstatt mit read-char und write-char , die mit Zeichen arbeiten. read-byte gibt ein aus dem Stream read-byte oder NIL am Ende der Datei zurück, wenn der zweite optionale Parameter NIL (andernfalls wird ein Fehler gemeldet).

Massenkopie

Eine genaue Kopie, effizienter als die vorige. Dies kann durch Lesen und Schreiben der Dateien mit großen Datenblöcken jedes Mal statt einzelner Bytes erfolgen:

(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 und write-sequence werden hier mit einem Puffer verwendet, der ein Vektor von Bytes ist (sie können Sequenzen von Bytes oder Zeichen verarbeiten). read-sequence füllt das Array mit den gelesenen Bytes jedes Mal und gibt die Anzahl der gelesenen Bytes zurück (die Anzahl kann geringer sein als die Größe des Arrays, wenn das Dateiende erreicht ist). Beachten Sie, dass das Array bei jeder Iteration destruktiv geändert wird.

Exaktes Kopieren Zeile für Zeile einer Datei

Das letzte Beispiel ist eine Kopie, bei der jede Zeile der Zeichen der Eingabedatei gelesen und in die Ausgabedatei geschrieben wird. Beachten Sie, dass wir, da wir eine exakte Kopie wünschen, prüfen müssen, ob die letzte Zeile der Eingabedatei durch ein Zeilenendezeichen abgeschlossen ist oder nicht. Aus diesem Grund verwenden wir die zwei Werte, die von read-line : eine neue Zeichenfolge, die die Zeichen der nächsten Zeile enthält, und einen booleschen Wert, der true ist , wenn die Zeile die letzte der Datei ist und nicht das letzte Zeilenvorschubzeichen enthält (s). In diesem Fall write-string wird anstelle von write-line , da erstere nicht eine neue Zeile am Ende der Zeile hinzufügen.

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

Beachten Sie, dass dieses Programm plattformunabhängig ist, da die Zeilenende- Marke (n) (variiert in verschiedenen Betriebssystemen) automatisch durch die verwaltet wird read-line und write-line - Funktionen.

Lesen und Schreiben ganzer Dateien in und aus Strings

Die folgende Funktion liest eine gesamte Datei in eine neue Zeichenfolge und gibt sie zurück:

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

Das Ergebnis ist NIL wenn die Datei nicht vorhanden ist.

Die folgende Funktion schreibt eine Zeichenfolge in eine Datei. Mit einem Schlüsselwortparameter wird angegeben, was zu tun ist, wenn die Datei bereits vorhanden ist (standardmäßig wird ein Fehler ausgegeben, die zulässigen Werte sind die des Makros 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 diesem Fall write-sequence kann substituiert sein mit write-string .



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow