如何使用drakma:http-request和flexistreams下载并保存文件

问题描述 投票:0回答:4

我正在尝试下载并保存 PDF,但在写入时失败并出现 EOF 错误。 这样做的正确方法是什么?

(with-open-file (file "/home/*/test.pdf"
                      :direction :io
                      :if-does-not-exist :create
                      :if-exists :supersede
                      :element-type '(unsigned-byte 8))
  (let ((input (drakma:http-request "http://www.fractalconcept.com/ex.pdf"
                                    :want-stream t)))
    (awhile (read-byte input)
      (write-byte it file))
    (close input)))
common-lisp binary-data
4个回答
8
投票

解决办法是我忘了使用

read-byte
的两个可选参数。

正确的方法是将

eof-error-p
eof-value
设置为
nil
:

(with-open-file (file "/home/*/test.pdf"
                      :direction :output
                      :if-does-not-exist :create
                      :if-exists :supersede
                      :element-type '(unsigned-byte 8))
  (let ((input (drakma:http-request "http://www.fractalconcept.com/ex.pdf"
                                    :want-stream t)))
    (awhile (read-byte input nil nil)
      (write-byte it file))
    (close input)))

2
投票
(ql:quickload "trivial-download")
(trivial-download:download URL FILE)

;几乎完全按照您的代码执行的操作,但以更大的块形式显示,并且可以显示进度条。

; QuickLisp 可以在 http://QuickLisp.org 找到。


1
投票

AWHILE 可在 ARNESI 包中找到。


0
投票

在撰写本文时,该答案不适用于 HTTPS URL。读取到 EOF 的流会导致

cl+ssl
意外关闭 SSL 流。还有一些更复杂的事情发生,请参阅 https://github.com/edicl/drakma/issues/138 了解更多信息。但是,我从 https://github.com/cl-plus-ssl/cl-plus-ssl/issues/166#issuecomment-1742175637 窃取的临时解决方法应该可以解决下载文件时的
cl+ssl
相关错误通过 HTTPS 使用
:want-stream t

(defun download-file (from-url to-file)
  (with-open-file (stream to-file :direction :output
                                  :if-exists :overwrite
                                  :if-does-not-exist :create
                                  :element-type '(unsigned-byte 8))
    (multiple-value-bind (input status-code response-headers)
        (drakma:http-request from-url :want-stream t :force-binary t)
      (unless (= 200 status-code)
        (error "Something wrong with the status code: ~s" status-code))
      (dotimes (x (parse-integer (cdr (assoc :content-length response-headers))))
        (write-byte (read-byte input nil nil) stream))
      (close input))))
© www.soinside.com 2019 - 2024. All rights reserved.