LISP: How to read content from a file and write it to another file?

I want to write a function that takes the names of two files as arguments and copies the contents from the first file to the second.

So far I've written a function that reads from a file:

(defun readFile (name)
 (let ((in (open name)))
  (format t "~a~%" (read-line in))
   (close in)))

      

And the function that writes the string to the file:

(defun writeFile (name content)
(with-open-file (stream name
    :direction :output
    :if-exists :overwrite
    :if-does-not-exist :create)
(format stream content)))

      

Following Savantes' instructions, I wrote the function again and it looks like this:

(defun read-write-to-file (input-file output-file)
(WITH-OPEN-FILE (output-stream output-file
         :direction :output
         :if-exists :new-version
         :if-does-not-exist :create)
  (WITH-OPEN-FILE (input-stream input-file
                 :direction :input)
        (FORMAT output-stream "~a" (READ input-stream nil 'eof))
)))

      

Now the only problem is that it doesn't read the whole file.

+2


source to share


5 answers


You have found with-open-file

. Use it for input and output. Don't use open

and close

instead.

Open both files, then write

into the output stream that you are read-line

from the input stream.

Yours WRITEFILE

obviously doesn't compile by the way.

Also, use correct names and indentations.



EDIT after updating the question:

read-line

reads one line. You can write it down with write-line

to preserve line endings. You need to do this in a loop to copy more lines.

Hint: you must write your names in lower case code. The reader closes them automatically. I decided to write WRITEFILE

above to show how your chosen name is handled internally. Capitalization doesn't matter. L

and L

match. Name parts are conditionally hyphenated in Lisp.

+4


source


The Common Lisp Cookbook does indeed answer your question:

http://cl-cookbook.sourceforge.net/io.html

See the Bulk I / O section at the bottom of this page.



With minor fixes and modifications, the code will look like this:

(defun my-copy-file (from-file to-file)
  (with-open-file (input-stream from-file
                :direction :input
                :element-type '(unsigned-byte 8))
    (with-open-file (output-stream to-file
                   :direction :output
                   :if-exists :supersede
                   :if-does-not-exist :create
                   :element-type '(unsigned-byte 8))
      (let ((buf (make-array 4096 :element-type (stream-element-type input-stream))))
    (loop for pos = (read-sequence buf input-stream)
       while (plusp pos)
       do (write-sequence buf output-stream :end pos))))))

      

It should be able to handle text files as well as binaries.

+4


source


Possibly a more concise solution, at least as fast as above, use copy-stream-to-stream from the excellent UIOP included in ASDF (and therefore with Quicklisp):

(require 'uiop)
(defun file-copy (source destination)
  (with-open-file (in source :direction :input)
    (with-open-file (out destination :direction :output)
      (uiop:copy-stream-to-stream in out))))

      

It should be as fast (if not more) as WRITE-SEQUENCE is the default. See the first link for more options copy-stream-to-stream

.

+3


source


First: Don't use 'READ' for this purpose, use 'READ-LINE'. "READ" performs read-macros, which opens a security hole. Conversely, you need to use "WRITE-LINE".

When you use "READ-LINE" you should see that it does exactly that: it reads exactly one line and returns that or (in your case) the character "EOF" when there is no line to read from the left. It also advances your read pointer after the next "EOL" (or something like that, I'm not really into the implementation specifics of streams), so when you do the next "READ-LINE" on that stream, the next line is read. Now you just have to read and write repeatedly until you hit the end of the file.

+1


source


This function copies the content from the first file to the second:

(defun my-function (first second)
  (cl-fad:copy-file first second))

      

(of course the cl-fad package must be downloaded)

Peter

+1


source







All Articles