如何在从球拍输入端口读取时显示HTTP文件下载进度

时间:2018-06-14 03:49:09

标签: http download progress-bar lisp racket

我的问题的根源是我需要能够获得已下载的总字节数,以显示进度条作为cli工具的一部分。

我通过HTTP GET请求下载文件。使用" Content-Length" http标题我可以看到我将用我的客户端下载文件的总大小。我想我会做旧的"下载/ total =进度" 公式。

我当前的实现可以获取文件并将其写入本地文件系统没有问题,因此请求和端口的设置按预期工作,我真的只需要一些指导如何了解输入端口是什么实际上做(事件?)我对Racket来说很新。

我使用以下库来发出http请求:

https://docs.racket-lang.org/http/index.html?q=http

有人提到协助实施进度条的有用程序:

https://github.com/greghendershott/http/blob/master/http/request.rkt#L505

这是我到目前为止所拥有的:

#| Basically just for debugging/testing, receives the default input-port 
#| and headers from the call/input-request procedure

(define (handle-entity in headers)
  (display headers)

  #| looking at the source this "read-entity/transfer-decoding-port" 
  #| should be useful for what I want to do
  (define decoded-port (read-entity/transfer-decoding-port in headers))

  #| writing the file works as expected, what I really want to do is
  #| is get the download progress as I write to the output-port
  (call-with-output-file "test.tar.gz"
                        (lambda (out)
                          (display (port->bytes decoded-port) out))))

(define (fetch)
  (call/input-request "1.1"
                      "GET"                       
                      "https://example.com/test.tar.gz"
                      empty
                      handle-entity #| will handle the input port created in this procedure
                      #:redirects 10))

1 个答案:

答案 0 :(得分:2)

您可以使用port-progress-evt有效地等待直到读取端口,并且您可以使用port-next-location来检查到目前为止已读取的字节数。您可以在另一个线程的循环中执行此操作以异步更新进度条。例如:

(define (listen-for-progress in)
  (sync (port-progress-evt in))
  (unless (port-closed? in)
    (define-values [line col pos] (port-next-location in))
    (printf "bytes read: ~a\n" pos)
    (listen-for-progress in)))

(define (read-with-progress in)
  (thread (λ () (listen-for-progress in)))
  #| do something with in |#)

另外,您应该使用copy-port代替port->bytes,然后使用display,因为copy-port会将输入端口流式传输到输出端口,但是 port->bytes会在开始写入输出端口之前将整个端口读入内存。