Sök…


Syntax

  • (read-char &optional stream eof-error-p eof-value recursive-p) => tecken
  • (write-char character &optional stream) => tecken
  • (read-line &optional stream eof-error-p eof-value recursive-p) => rad, saknas-newline-p
  • (write-line line &optional stream) => rad

parametrar

Parameter Detalj
stream Strömmen att läsa från eller skriva till.
eof-error-p Skulle ett fel signaleras om filens slut uppstår.
eof-value Vilket värde ska returneras om eof stöter på och eof-error-p är falsk.
recursive-p Kallas läsoperationen rekursivt från READ . Vanligtvis ska detta lämnas som NIL .
character Karaktären att skriva, eller karaktären som lästes.
line Raden som ska skrivas eller raden som lästes.

Skapa input-strömmar från strängar

Makroen WITH-INPUT-FROM-STRING kan användas för att skapa en ström från en sträng.

(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

Detsamma kan göras manuellt med hjälp av 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)))

Skriva utdata till en sträng

Makroen WITH-OUTPUT-TO-STRING kan användas för att skapa en strängutström och returnera den resulterande strängen i slutet.

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

Detsamma kan göras manuellt med hjälp av MAKE-STRING-OUTPUT-STREAM och GET-OUTPUT-STREAM-STRING .

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

Grå strömmar

Grå strömmar är en icke-standardförlängning som tillåter användardefinierade strömmar. Det tillhandahåller klasser och metoder som användaren kan utöka. Du bör kolla implementeringshandboken för att se om den ger grå strömmar.

För ett enkelt exempel kan en teckeninmatningsström som returnerar slumpmässiga tecken implementeras på följande sätt:

(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

Läser fil

En fil kan öppnas för läsning som en ström med 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

Detsamma kan göras manuellt med OPEN och 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)))

Observera att READ-LINE skapar en ny sträng för varje rad. Detta kan vara långsamt. Vissa implementationer ger en variant som kan läsa en rad i en strängbuffert. Exempel: READ-LINE-INTO för Allegro CL.

Skriva till en fil

En fil kan öppnas för skrivning som en ström med 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)))

Detsamma kan göras manuellt med OPEN och 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))

Kopierar en fil

Kopiera byte-per-byte av en fil

Följande funktion kopierar en fil till en annan genom att utföra en exakt byte-per-byte-kopia, ignorera typen av innehåll (som kan vara antingen rader med tecken i någon kodning eller binär data):

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

Typen (unsigned-byte 8) är typen av 8-bitarsbyte. Funktionerna read-byte och write-byte fungerar på byte istället för read-char och write-char som fungerar på tecken. read-byte returnerar en byte-läsning från strömmen, eller NIL i slutet av filen om den andra valfria parametern är NIL (annars signalerar det ett fel).

Bulkkopia

En exakt kopia, effektivare den föregående. kan göras genom att läsa och skriva filerna med stora bitar data varje gång, istället för enstaka byte:

(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 och write-sequence används här med en buffert som är en vektor av byte (de kan fungera på sekvenser av byte eller tecken). read-sequence fyller matrisen med de byte som läses varje gång och returnerar antalet lästa byte (som kan vara mindre än storleken på matrisen när slutet på filen nås). Observera att matrisen är destruktivt modifierad vid varje iteration.

Exakt kopieringsrad per rad för en fil

Det sista exemplet är en kopia som utförs genom att läsa varje rad med tecken i inmatningsfilen och skriva den till utdatafilen. Observera att eftersom vi vill ha en exakt kopia måste vi kontrollera om den sista raden i inmatningsfilen är avslutad eller inte av ett slut på radtecken. Av den anledningen använder vi de två värden som returneras av read-line : en ny sträng som innehåller tecknen på nästa rad och ett booleskt värde som är sant om linjen är den sista i filen och inte innehåller det sista nyradstecknet (s). I det här fallet write-string används i stället för write-line , eftersom den förstnämnda inte lägga till en ny rad i slutet av raden.

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

Observera att detta program är plattformsoberoende, eftersom radmatningstecken (s) (varierar i olika operativsystem) automatiskt hanteras av read-line och write-line

Läsa och skriva hela filer till och från strängar

Följande funktion läser en hel fil i en ny sträng och returnerar den:

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

Resultatet är NIL om filen inte finns.

Följande funktion skriver en sträng till en fil. En nyckelordsparameter används för att specificera vad man ska göra om filen redan finns (som standard orsakar den ett fel, värden som är tillåtna är de för makro 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)))

I detta fall kan write-sequence ersättas med write-string .



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow