Szukaj…


Składnia

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

Parametry

Parametr Szczegół
stream Strumień do odczytu lub zapisu.
eof-error-p Powinien być sygnalizowany błąd w przypadku napotkania końca pliku.
eof-value Jaką wartość należy zwrócić w przypadku napotkania eof-error-p , a eof-error-p ma wartość false.
recursive-p Czy operacja odczytu jest wywoływana rekurencyjnie z READ . Zwykle należy to pozostawić jako NIL .
character Znak do napisania lub znak, który został odczytany.
line Linia do zapisu lub linia, która została przeczytana.

Tworzenie strumieni wejściowych z ciągów

Makro WITH-INPUT-FROM-STRING można wykorzystać do utworzenia strumienia z łańcucha.

(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

To samo można zrobić ręcznie za pomocą 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)))

Zapisywanie danych wyjściowych do łańcucha

Makra WITH-OUTPUT-TO-STRING można użyć do utworzenia strumienia wyjściowego łańcucha i zwrócenia wynikowego łańcucha na końcu.

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

To samo można zrobić ręcznie, używając MAKE-STRING-OUTPUT-STREAM i GET-OUTPUT-STREAM-STRING .

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

Szare strumienie

Szare strumienie są niestandardowym rozszerzeniem, które umożliwia strumienie zdefiniowane przez użytkownika. Zapewnia klasy i metody, które użytkownik może rozszerzyć. Powinieneś sprawdzić instrukcję implementacji, aby sprawdzić, czy zapewnia ona strumienie Graya.

W prostym przykładzie strumień wejściowy znaków, który zwraca losowe znaki, można zaimplementować w następujący sposób:

(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

Odczytywanie pliku

Plik można otworzyć do odczytu jako strumień przy użyciu makra 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

To samo można zrobić ręcznie, używając OPEN i 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)))

Zauważ, że READ-LINE tworzy nowy ciąg dla każdej linii. To może być powolne. Niektóre implementacje zapewniają wariant, który może wczytywać linię do bufora łańcuchów. Przykład: READ-LINE-INTO dla Allegro CL.

Zapis do pliku

Plik można otworzyć w celu zapisania jako strumień przy użyciu makra 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)))

To samo można zrobić ręcznie za pomocą OPEN i 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))

Kopiowanie pliku

Skopiuj bajt na bajt pliku

Poniższa funkcja kopiuje plik do innego, wykonując dokładną kopię bajt po bajcie, ignorując rodzaj zawartości (która może być albo wierszami znaków w danych kodowania lub danymi binarnymi):

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

Typ (unsigned-byte 8) to typ 8-bitowych bajtów. Funkcje read-byte i write-byte działają na bajtach, zamiast read-char i write-char które działają na znakach. read-byte zwraca bajt odczytany ze strumienia lub NIL na końcu pliku, jeśli drugim opcjonalnym parametrem jest NIL (w przeciwnym razie sygnalizuje błąd).

Kopia zbiorcza

Dokładna kopia, bardziej wydajna od poprzedniej. można to zrobić, odczytując i zapisując pliki z dużymi porcjami danych za każdym razem, zamiast pojedynczych bajtów:

(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 są tutaj używane z buforem, który jest wektorem bajtów (mogą działać na sekwencji bajtów lub znaków). read-sequence wypełnia tablicę za każdym razem odczytanymi bajtami i zwraca liczbę odczytanych bajtów (która może być mniejsza niż rozmiar tablicy po osiągnięciu końca pliku). Zauważ, że tablica jest destrukcyjnie modyfikowana przy każdej iteracji.

Dokładne kopiowanie linia po linii pliku

Ostatnim przykładem jest kopia wykonywana przez odczytanie każdego wiersza znaków pliku wejściowego i zapisanie go w pliku wyjściowym. Zauważ, że ponieważ potrzebujemy dokładnej kopii, musimy sprawdzić, czy ostatni wiersz pliku wejściowego jest zakończony, czy nie znakiem końca wiersza. Z tego powodu używamy dwóch wartości zwracanych przez read-line : nowy ciąg znaków zawierający znaki następnego wiersza oraz wartość logiczna, która jest prawdziwa, jeśli wiersz jest ostatnim plikiem i nie zawiera ostatniego znaku nowej linii (s). W tym przypadku zamiast write-line jest write-string write-line , ponieważ ten pierwszy nie dodaje nowego wiersza na końcu wiersza.

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

Należy pamiętać, że ten program jest niezależny od platformy, ponieważ znak (znaki) nowej linii (różne w różnych systemach operacyjnych) jest automatycznie zarządzany przez funkcje read-line write-line .

Odczytywanie i zapisywanie całych plików do iz ciągów

Poniższa funkcja odczytuje cały plik do nowego ciągu i zwraca go:

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

Wynik to NIL jeśli plik nie istnieje.

Poniższa funkcja zapisuje ciąg do pliku. Parametr słowa kluczowego służy do określenia, co należy zrobić, jeśli plik już istnieje (domyślnie powoduje błąd, dopuszczalne są wartości makra 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)))

W takim przypadku write-sequence można zastąpić write-string .



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow