2010-09-28 50 views
6

Tôi muốn đọc nội dung của một tệp trong danh sách. Một số nỗ lực của tôi cho đến nay đã có -Làm cách nào để đọc nội dung của một tệp trong danh sách trong Lisp?

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

Không có cách nào trong số này hoạt động. Bất cứ ai có thể cho tôi biết một cách? Hoặc thậm chí tốt hơn - làm thế nào để đưa tất cả các nội dung vào một mảng?

Trả lời

14

Làm thế nào về

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

(với mở file (f filename) Tại sao bạn có một f trước tên tập tin đó? những gì hiện thu thập dòng làm gì? Và làm thế nào mà cộng tác với dòng trong khi ở cuối? – Sterling

+3

'with-open-file' mở tệp có tên' filename' và liên kết luồng với 'f'. 'collection' thu thập các giá trị khác nhau của' dòng' trong một danh sách, cho đến khi 'while' là' nil'. Common Lisp HyperSpec và thực tế Common Lisp là bạn của bạn! –

+2

Nói cách khác, 'with-open-file' thực hiện tất cả công việc của' open' và 'close' và' let'. –

8

Đâu là những vấn đề?

(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 

DO sẽ chỉ thực hiện điều gì đó cho các tác dụng phụ.

COLLECT sẽ thu thập kết quả và LOOP sau đó sẽ trả về danh sách các giá trị được thu thập khi thoát.

Như đã đề cập, sử dụng WITH-OPEN-FILE thay vì OPEN/CLOSE. WITH-OPEN-FILE sẽ đóng tệp khi rời khỏi phạm vi động. Không chỉ từ một lối thoát bình thường, mà còn trên các điều kiện lỗi sử dụng UNWIND-PROTECT.

Nếu bạn muốn đọc nội dung của tệp, bạn có thể sử dụng READ-SEQUENCE. Với những vấn đề thông thường. Ví dụ khi bạn đọc một tệp ASCII dưới dạng văn bản thành một chuỗi, chuỗi có thể ngắn hơn tệp. Ví dụ, Lisp thường sẽ đại diện cho CRLF nội bộ với một ký tự đơn, trên các nền tảng mà CRLF là dòng mới. Một ví dụ khác: trong Unicode hỗ trợ việc triển khai mã UTF-8 trong tệp có thể được thay thế bằng một ký tự đơn.

+0

+1 để mô tả lỗi! –

2

tôi sẽ thêm các thư viện trong

chỉnh sửa thậm chí dễ dàng hơn, với uiop, được bao gồm trong asdf:.

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

https://github.com/fare/asdf/blob/master/uiop/stream.lisp#L445

cũng có

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

Với Alexandria's read-file-into-string và tách chuỗi:

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

Với str:

(str:lines (str:from-file "file.txt")) 
Các vấn đề liên quan