我想从http
或https
网址下载二进制文件,如:
URI('https://www.google.com/favicon.ico').download('google.ico')
我为此编写了这样的方法:
module URI
def download(file)
File.open(file, 'wb') {|f| f.write(open(self).read)}
end
end
此方法最终出现错误ArgumentError: extra arguments
,而以下代码正在运行。
file = 'google.ico'
url = 'https://www.google.com/favicon.ico')
File.open(file, 'wb') {|f| f.write(open(url).read)}
我做错了什么?我该如何解决?
答案 0 :(得分:1)
URI module doesn't download file. File class doesn't either. open
comes from open-uri
stdlib which is why it works in your 2nd example. If you have curl
in your system this should work:
module URI
def self.download(file_url)
filename = file_url.split('/').last
`curl -O #{file_url}`
end
end
If you DON'T have curl
use open-uri
require 'open-uri'
module URI
def self.download(file_url)
filename = file_url.split('/').last
File.open(filename, "wb") do |saved_file|
open(file_url, "rb") do |read_file|
saved_file.write(read_file.read)
end
end
end
end
And call it like this
URI.download('https://www.google.com/favicon.ico')
Note, URI behaves like more like a class so you need to define the method on the base object self
otherwise you'll need to create an instance, but since it's just a module, use def self.some_method(some_arg)
to be able to call URL.some_method(some_arg)
While this works, it is not recommended for production. Why do you wanna monkey patch URI when you can simply write your own module which does this?
You're better off doing something like this:
module SimpleFileDownload
require 'open-uri'
def self.download(file_url)
filename = file_url.split('/').last
File.open(filename, "wb") do |saved_file|
open(file_url, "rb") do |read_file|
saved_file.write(read_file.read)
end
end
end
end
and call it like:
SimpleFileDownload.download('https://www.google.com/favicon.ico')
答案 1 :(得分:1)
我以为我是从Kernel.open
拨打open-uri
,但是在URI
OpenURI::OpenRead
模块内部被调用。
首先我添加了binding.pry
module URI
def download(file)
binding.pry
File.open(file, 'wb') {|f| f.write(open(self).read)}
end
end
并检查调用哪个方法:
pry(#<URI::HTTPS>)> show-method open
From: /Users/ironsand/.rbenv/versions/2.4.3/lib/ruby/2.4.0/open-uri.rb @ line 720:
Owner: OpenURI::OpenRead
Visibility: public
Number of lines: 3
def open(*rest, &block)
OpenURI.open_uri(self, *rest, &block)
end
pry(#<URI::HTTPS>)> exit
pry(main)> show-method open
From: /Users/ironsand/.rbenv/versions/2.4.3/lib/ruby/2.4.0/open-uri.rb @ line 29:
Owner: Kernel
Visibility: private
Number of lines: 11
def open(name, *rest, &block) # :doc:
if name.respond_to?(:open)
name.open(*rest, &block)
elsif name.respond_to?(:to_str) &&
%r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ name &&
(uri = URI.parse(name)).respond_to?(:open)
uri.open(*rest, &block)
else
open_uri_original_open(name, *rest, &block)
end
end
要使用正确的方法,我应该明确调用该方法。
module URI
def download(file)
File.open(file, 'wb') {|f| f.write(OpenURI.open_uri(self).read)}
end
end
上面的代码按预期工作。