2

我想计算一个平面文件中的行数,所以我写了代码:

(defun ff-rows (dir file)
  (with-open-file (str (make-pathname :name file
                                      :directory dir)
                                      :direction :input)
    (let ((rownum 0))
      (do ((line (read-line str file nil 'eof)
                 (read-line str file nil 'eof)))
          ((eql line 'eof) rownum)
        (incf rownum )))))

但是我得到了错误:

*** - READ: input stream
       #<INPUT BUFFERED FILE-STREAM CHARACTER #P"/home/lambda/Documents/flatfile"
         @4>
      ends within an object

请问这里有什么问题吗?我试着数行数;这个操作很好。

注意:这是我用来测试函数的平面文件的内容:

2 3 4 6 2 
1 2 3 1 2
2 3 4 1 6
4

3 回答 3

4

据我所知,问题是您的 (read-line ... ) 调用中的“文件”。

基于hyperspec, read-line 的签名是:

read-line &optional input-stream eof-error-p eof-value recursive-p
=> line, missing-newline-p

...这意味着“文件”被解释为 eof-error-p,nil 被解释为 eof-value,'eof 被解释为递归-p。不用说,问题接踵而至。如果您从 read-line 调用中删除“文件”(例如(read-line str nil :eof)),代码运行良好,无需在我的机器上进行进一步修改(AllegroCL 和 LispWorks。)

于 2012-11-15T12:19:24.797 回答
4

短一点。

(defun ff-rows (dir file)
  (with-open-file (stream (make-pathname :name file
                                         :directory dir)
                          :direction :input)
    (loop for line = (read-line stream nil nil)
          while line count line)))

请注意,您需要获得READ-LINE正确的参数。首先是流。文件不是参数列表的一部分。

将路径名处理混合到一般的 Lisp 函数中通常也不是一个好主意。

(defun ff-rows (pathname)
  (with-open-file (stream pathname :direction :input)
    (loop for line = (read-line stream nil nil)
          while line count line)))

在另一个函数或其他代码中进行路径名处理。将路径名组件传递给函数通常是错误的设计。传递完整的路径名。

使用 LispWorks 文件选择器:

CL-USER 2 > (ff-rows (capi:prompt-for-file "some file"))
27955

更好的是所有基本 I/O 函数都在流上工作,而不是在路径名上工作。因此,您可以计算网络流、串行线或其他流中的行数。

于 2012-11-15T13:14:34.340 回答
1
(defun ff-rows (dir file)
  (with-open-file
      (str (make-pathname :name file :directory dir)
           :direction :input)
    (let ((result 0))
      (handler-case
          (loop (progn (incf result) (read-line str)))
        (end-of-file () (1- result))
        (error () result)))))

现在,当然,如果你比我更迂腐,你可以指定你想准确处理什么样的错误,但对于简单的例子,这将是可行的。

编辑:我认为@Moritz 更好地回答了这个问题,但这可能是如何利用抛出的错误read-line而不是试图避免它的一个例子。

于 2012-11-15T11:46:31.157 回答