【问题标题】:LISP: How to read content from a file and write it in another file?LISP:如何从文件中读取内容并将其写入另一个文件?
【发布时间】:2025-12-24 16:05:11
【问题描述】:

我想编写一个函数,将两个文件的名称作为参数并将内容从第一个文件复制到第二个文件。

到目前为止,我编写了一个从文件读取的函数:

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

还有一个将字符串写入文件的函数:

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

按照 Savantes 的说明,我再次编写了函数,结果如下:

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

现在唯一的问题是它没有读取整个文件。

【问题讨论】:

    标签: file io lisp


    【解决方案1】:

    Common Lisp 食谱实际上包含了您问题的答案:

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

    请参阅该页面底部的“批量 I/O”部分。

    稍加修正和修改后,代码将如下所示:

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

    这应该能够处理文本文件以及二进制文件。

    【讨论】:

    • 你能不能不用LET,只复制字节:(loop for b = (read-byte in-stream nil) while b do (write-byte b out-stream))
    • @peter 你可以,但一次读取多个字节可能更快。
    【解决方案2】:

    您找到了with-open-file。将其用于输入和输出。不要使用 openclose 代替。

    打开这两个文件,然后将write 输出到输出流,就像你从输入流中read-line 一样。

    顺便说一句,您的WRITEFILE 显然无法编译。

    另外,请使用正确的名称和缩进。

    问题更新后编辑:

    Read-line 读取一行。您可以使用write-line 编写它,以便保留行尾。您需要循环执行此操作才能复制更多行。

    提示:你应该在代码中用小写字母写你的名字。阅读器会自动将它们大写。我选择在上面写WRITEFILE 来展示你选择的名字在内部是如何处理的。大小写无关。 Ll 是一样的。在 Lisp 代码中,部分名称通常用连字符分隔。

    【讨论】:

    • 我按照您的说明编写了函数,并在此处获得了一些帮助:link 这是函数,但现在问题是它只读取一行:'(defun read-write-to -file(输入文件输出文件)(WITH-OPEN-FILE(输出流输出文件:方向:输出: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)) )))' 如何让它读取整个文件?
    • @seby598 请使用此评论中发布的代码更新您的问题。这样,人们就可以看到您在解决方案方面取得的进展并为您提供帮助,而无需筛选所有答案和 cmets。
    【解决方案3】:

    可能是一个更简洁的解决方案,至少与上述一样快,使用来自优秀的UIOP 包的copy-stream-to-stream,包含在 ASDF 中(因此也包含在 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))))
    

    它应该和默认使用 WRITE-SEQUENCE 一样快(如果不是更快的话)。有关copy-stream-to-stream 的其他选项,请参阅第一个链接。

    【讨论】:

      【解决方案4】:

      此函数将第一个文件的内容复制到第二个文件:

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

      (当然要加载cl-fad包)

      彼得

      【讨论】:

      • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
      • @JAL 谢谢,我刚刚添加了额外的上下文。
      【解决方案5】:

      首先:不要为此使用“READ”,请使用“READ-LINE”。 'READ' 执行读取宏,这会打开一个安全漏洞。相反,您需要使用“WRITE-LINE”。

      当您使用 'READ-LINE' 时,您应该看到它确实做到了:它只读取一行并返回该行,或者(在您的情况下)当没有行可读取时返回符号 'EOF'。它还会在下一个“EOL”之后推进您的读取指针(或类似的东西,我不太熟悉流的实现细节),因此当您在该流上执行下一个“READ-LINE”时,会读取下一行。您现在只需要反复读写,直到遇到文件末尾。

      【讨论】:

        最近更新 更多