Viết trình download có thanh tiến trình với ruby
Ruby
115
downloader
1
aria2
1
White

Hieu Nguyen viết ngày 19/08/2016

Khi làm việc với Ruby và Rails, có lẽ không ít lần các bạn đã gặp các tác vụ download file về server của mình. Ruby hỗ trợ nhiều công cụ download khác nhau, từ đơn giản đến phức tạp, như Net::HTTP, OpenURI hay Mechanize, ... Tuy nhiên, các thư viện này không có sẵn chức năng hiển thị tiến trình (progress) cho người dùng, do đó đôi lúc bạn sẽ không biết là chương trình của mình đang chạy hay là đã treo rồi.

Bạn có thể dùng kết hợp gem ruby-progressbarOpenURI để lấy thông tin và hiển thị tiến trình download. Một thanh tiến trình để hiển thị có thể được khởi tạo đơn giản như sau:

progress_bar = ProgressBar.create(
  starting_at: 0,
  total: nil,
  format: "%a %B %p%% %r KB/sec",
  rate_scale: lambda { |rate| rate / 1024 }
)

Sau khi lấy được header của file, bạn cần gán nó cho độ dài của thanh tiến trình. OpenURI hỗ trợ content_length_proc callback để làm điều này:

content_length_proc = Proc.new { |content_length|
  progress_bar.total = content_length
}

Bạn cần cập nhật độ dài của thanh tiến trình mỗi khi dữ liệu được tải về. OpenURI cũng hỗ trợ progress_proc callback để giúp bạn làm điều này:

progress_proc = Proc.new { |bytes_transferred|
  progress_bar.progress = bytes_transferred
}

Đôi khi, header của file sẽ không chính xác sẽ dẫn đến việc số byte tải về vượt quá độ dài của thanh tiến trình, khi đó ruby-progressbar sẽ trả về một exception. Bạn cũng cần xử lý trường hợp này:

progress_proc = Proc.new { |bytes_transferred|
  if progress_bar.total && progress_bar.total < bytes_transferred
    progress_bar.total = nil
  end
  progress_bar.progress = bytes_transferred
}

Bạn có thể xem đầy đủ code của chương trình này trên

require 'open-uri'
require 'fileutils'
require 'ruby-progressbar'
progress_bar = ProgressBar.create(
starting_at: 0,
total: nil,
format: "%a %B %p%% %r KB/sec",
rate_scale: lambda { |rate| rate / 1024 }
)
content_length_proc = Proc.new { |content_length|
progress_bar.total = content_length
}
progress_proc = Proc.new { |bytes_transferred|
if progress_bar.total && progress_bar.total < bytes_transferred
progress_bar.total = nil
end
progress_bar.progress = bytes_transferred
}
open(link, "rb", content_length_proc: content_length_proc, progress_proc: progress_proc) do |page|
File.open(file_path, "wb") do |file|
file.write(page.read)
end
end
view raw gistfile1.rb hosted with ❤ by GitHub
. Như vậy là bạn đã có một trình download với thanh tiến trình rất đẹp rồi nhỉ:

alt text

Ngoài ra, bạn còn có thể tận dụng các phần mềm download hiện có trên hệ thống bằng việc sử dụng hàm system. Hầu hết các trình download này đều mặc định hiển thị thanh tiến trình khi download. Sau đây là implementation của một số trình download phổ biến.

CURL

curl là trình download phổ biến nhất trên các hệ điều hành Unix-based. Được cài sẵn trên hầu hết các distro Linux và các phiên bản Mac. Bạn có thể dùng gem Curb hoặc như sau:

system("curl -A 'Wget/1.8.1' --retry 10 --retry-delay 5 --retry-max-time 4  -L #{link} -o #{file_path}")

WGET

wget hầu như luôn có trên các distro Linux, còn trên Mac thì bạn thường phải cài thêm.

system("wget -c #{link} -O #{file_path}")

ARIA2

aria2 là một trình download gọn nhẹ, có thể cài đặt đơn giản trên Linux hoặc Mac. Điểm mạnh của aria2 là sử dụng nhiều connection song song khiến cho tốc độ download nhanh gấp 2-3 lần curl hay wget.

system("aria2c #{link} -U 'Wget/1.8.1' -x4 -d #{File.dirname(file_path)} -o #{File.basename(file_path)}")
Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Hieu Nguyen

22 bài viết.
10 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
11 4
Đối với những người đã từng xây dựng API server, chắc hẳn ai cũng đã từng hơn một lần đau đầu với việc lựa chọn thư viện JSON. Bài viết sau đây hi ...
Hieu Nguyen viết 3 năm trước
11 4
White
11 0
Như đã nói trong (Link), mình sẽ chia sẻ tổng hợp kết quả của các benchmark mình đã dùng để so sánh tốc độ render JSON của các thư viện phổ biến hi...
Hieu Nguyen viết 3 năm trước
11 0
White
6 4
Hãy tưởng tượng: bạn là một tín đồ của Rails và DHH. Bạn thần tượng (Link) và luôn dùng callback để thực hiện các tác vụ liên quan đến persistence ...
Hieu Nguyen viết 1 năm trước
6 4
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
22 bài viết.
10 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!