【问题标题】:How can I read the contents of a file into a list in Lisp?如何将文件的内容读入 Lisp 的列表中?
【发布时间】:2011-04-18 08:27:52
【问题描述】:

我想将文件的内容读入列表。到目前为止,我的一些尝试是 -

(defun get-file (filename)
  (let ((x (open filename)))
    (when x
      (loop for line = (read-line x nil)
     while line do (list line)))
    (close x)))

(defun get-file (filename)
  (let ((x (open filename :if-does-not-exist nil)) (contents (list nil)))
    (when x
      (loop for line = (read-line x nil)
     while line do (cons contents line)))
    (close x) contents))

(defun get-file (filename)
  (let ((x (open filename :if-does-not-exist nil)) (contents nil))
    (when x
      (loop for line = (read-line x nil)
     while line do (append contents line)))
    (close x) contents))

这些都不起作用。谁能告诉我一个方法?或者更好 - 如何将所有内容放入数组中?

【问题讨论】:

    标签: list file-io lisp common-lisp


    【解决方案1】:

    怎么样

    (defun get-file (filename)
      (with-open-file (stream filename)
        (loop for line = (read-line stream nil)
              while line
              collect line)))
    

    【讨论】:

    • (with-open-file (f filename) 为什么你的文件名前面有一个 f?collecting 行是做什么的?和结尾的 while 行如何协作?
    • with-open-file 打开名为filename 的文件并将流与f 关联。 collectingline 的各种值收集到一个列表中,直到whilenil。 Common Lisp HyperSpec 和 Practical Common Lisp 是你的朋友!
    • 换句话说,with-open-file 完成了openclose 以及let 的所有工作。
    • stream 是一个比 f 更好的名字。将 WHILE 移到 COLLECT 前面也很有用。
    【解决方案2】:

    我将添加库。

    编辑更容易,uiop 包含在 ASDF 中:

    (uiop:read-file-lines "file.txt")
    

    https://common-lisp.net/project/asdf/uiop.html#UIOP_002fSTREAM

    还有

    (uiop:read-file-string "file")
    

    使用Alexandria's read-file-into-string 和拆分序列:

    (alexandria:read-file-into-string "file.txt")
    (split-sequence:split-sequence #\Newline *)
    

    str:

    (str:lines (str:from-file "file.txt"))
    

    关于文件的更多食谱:https://lispcookbook.github.io/cl-cookbook/files.html

    【讨论】:

    • 这应该成为公认的答案。每次我需要加载文件时,我都会编写自己的实用程序函数。现在我了解到我的编译器有两个(一个用于列表,一个用于单个字符串)。谢谢!
    【解决方案3】:

    问题出在哪里?

    (defun get-file (filename)
      (let ((x (open filename)))
        (when x
          (loop for line = (read-line x nil)
                while line
                do (list line)))    ; <-- you are not collecting, just doing
        (close x)))                 ; <- the function returns the value of CLOSE
    
    (defun get-file (filename)
      (let ((x (open filename :if-does-not-exist nil))
            (contents (list nil)))
        (when x
          (loop for line = (read-line x nil)
                while line
                do (cons contents line)))  ; <-- again, the cons goes nowhere
        (close x) contents))               ; <-- CONTENTS has never been changed
    
    (defun get-file (filename)
      (let ((x (open filename :if-does-not-exist nil))
            (contents nil))
        (when x
          (loop for line = (read-line x nil)
                while line
                do (append contents line)))  ; <- again the result goes nowhere
        (close x) contents))                 ; <-- CONTENTS has never been changed
    

    循环

    LOOPDO 子句只会执行一些副作用。

    COLLECT 将收集结果,LOOP 然后将在退出时返回收集的值列表。

    文件的打开和关闭

    如前所述,使用WITH-OPEN-FILE 而不是OPEN/CLOSEWITH-OPEN-FILE 将在离开动态范围时关闭文件。不仅从正常退出,而且在错误情况下,通过使用UNWIND-PROTECT 来确保执行。

    读取文件内容

    如果要读取文件的内容,可以使用函数READ-SEQUENCE。与通常的问题。例如,当您将 ASCII 文件作为文本读入字符串时,字符串可能比文件短。例如,在 CRLF 是换行符的平台上,Common Lisp 将在内部用单个字符表示 CRLF。另一个例子:在支持 Unicode 的实现中,文件中的 UTF-8 代码可以用单个字符替换。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-13
      • 1970-01-01
      • 2020-01-13
      相关资源
      最近更新 更多