HTTP를 통해 바이너리 파일을 다운로드하려면 어떻게합니까?
Ruby를 사용하여 HTTP를 통해 바이너리 파일을 다운로드하고 저장하려면 어떻게합니까?
URL은 http://somedomain.net/flv/sample/sample.flv
입니다.
저는 Windows 플랫폼을 사용하고 있으며 외부 프로그램을 실행하지 않는 것을 선호합니다.
가장 간단한 방법은 플랫폼 별 솔루션입니다.
#!/usr/bin/env ruby
`wget http://somedomain.net/flv/sample/sample.flv`
아마 당신은 찾고 있습니다 :
require 'net/http'
# Must be somedomain.net instead of somedomain.net/, otherwise, it will throw exception.
Net::HTTP.start("somedomain.net") do |http|
resp = http.get("/flv/sample/sample.flv")
open("sample.flv", "wb") do |file|
file.write(resp.body)
end
end
puts "Done."
편집 : 변경되었습니다. 감사합니다.
편집 2 : 다운로드하는 동안 파일의 일부를 저장하는 솔루션 :
# instead of http.get
f = open('sample.flv')
begin
http.request_get('/sample.flv') do |resp|
resp.read_body do |segment|
f.write(segment)
end
end
ensure
f.close()
end
나는 이것이 오래된 질문이라는 것을 알고 있지만 Google에서 나를 던졌고 더 간단한 대답을 찾았습니다.
에서 Railscasts # 179 , 라이언 베이츠는 루비 표준 클래스를 사용 OpenURI 많은 같은 질문을 받았다 무엇 할 :
( 경고 : 테스트되지 않은 코드입니다. 변경 / 조정해야 할 수도 있습니다.)
require 'open-uri'
File.open("/my/local/path/sample.flv", "wb") do |saved_file|
# the following "open" is provided by open-uri
open("http://somedomain.net/flv/sample/sample.flv", "rb") do |read_file|
saved_file.write(read_file.read)
end
end
다음은 파일을 사용하는 Ruby http open(name, *rest, &block)
입니다.
require "open-uri"
require "fileutils"
def download(url, path)
case io = open(url)
when StringIO then File.open(path, 'w') { |f| f.write(io) }
when Tempfile then io.close; FileUtils.mv(io.path, path)
end
end
여기서 가장 큰 장점은 간결하고 간단 open
합니다. 많은 양의 리프팅이 있기 때문 입니다. 그리고 메모리에서 전체 응답을 읽지 않습니다.
이 open
방법은> 1kb 이상의 응답을 a로 스트리밍합니다 Tempfile
. 이 지식을 활용하여이 린 다운로드 파일 방법을 구현할 수 있습니다. 여기 에서 OpenURI::Buffer
구현을 참조 하십시오.
사용자가 제공 한 입력에주의하십시오! 사용자 입력에서 오는 open(name, *rest, &block)
경우 안전하지 않습니다 name
!
Ruby의 net / http 문서 에있는 예제 3은 HTTP를 통해 문서를 다운로드하고 파일을 메모리에로드하는 대신 파일을 출력하는 방법을 보여줍니다 (예 : Dejw의 답변에 표시된대로 파일에 2 진 쓰기로 대체).
더 복잡한 사례는 동일한 문서에서 더 아래에 표시됩니다.
You can use open-uri, which is a one liner
require 'open-uri'
content = open('http://example.com').read
Or by using net/http
require 'net/http'
File.write("file_name", Net::HTTP.get(URI.parse("http://url.com")))
Expanding on Dejw's answer (edit2):
File.open(filename,'w'){ |f|
uri = URI.parse(url)
Net::HTTP.start(uri.host,uri.port){ |http|
http.request_get(uri.path){ |res|
res.read_body{ |seg|
f << seg
#hack -- adjust to suit:
sleep 0.005
}
}
}
}
where filename
and url
are strings.
The sleep
command is a hack that can dramatically reduce CPU usage when the network is the limiting factor. Net::HTTP doesn't wait for the buffer (16kB in v1.9.2) to fill before yielding, so the CPU busies itself moving small chunks around. Sleeping for a moment gives the buffer a chance to fill between writes, and CPU usage is comparable to a curl solution, 4-5x difference in my application. A more robust solution might examine progress of f.pos
and adjust the timeout to target, say, 95% of the buffer size -- in fact that's how I got the 0.005 number in my example.
Sorry, but I don't know a more elegant way of having Ruby wait for the buffer to fill.
Edit:
This is a version that automatically adjusts itself to keep the buffer just at or below capacity. It's an inelegant solution, but it seems to be just as fast, and to use as little CPU time, as it's calling out to curl.
It works in three stages. A brief learning period with a deliberately long sleep time establishes the size of a full buffer. The drop period reduces the sleep time quickly with each iteration, by multiplying it by a larger factor, until it finds an under-filled buffer. Then, during the normal period, it adjusts up and down by a smaller factor.
My Ruby's a little rusty, so I'm sure this can be improved upon. First of all, there's no error handling. Also, maybe it could be separated into an object, away from the downloading itself, so that you'd just call autosleep.sleep(f.pos)
in your loop? Even better, Net::HTTP could be changed to wait for a full buffer before yielding :-)
def http_to_file(filename,url,opt={})
opt = {
:init_pause => 0.1, #start by waiting this long each time
# it's deliberately long so we can see
# what a full buffer looks like
:learn_period => 0.3, #keep the initial pause for at least this many seconds
:drop => 1.5, #fast reducing factor to find roughly optimized pause time
:adjust => 1.05 #during the normal period, adjust up or down by this factor
}.merge(opt)
pause = opt[:init_pause]
learn = 1 + (opt[:learn_period]/pause).to_i
drop_period = true
delta = 0
max_delta = 0
last_pos = 0
File.open(filename,'w'){ |f|
uri = URI.parse(url)
Net::HTTP.start(uri.host,uri.port){ |http|
http.request_get(uri.path){ |res|
res.read_body{ |seg|
f << seg
delta = f.pos - last_pos
last_pos += delta
if delta > max_delta then max_delta = delta end
if learn <= 0 then
learn -= 1
elsif delta == max_delta then
if drop_period then
pause /= opt[:drop_factor]
else
pause /= opt[:adjust]
end
elsif delta < max_delta then
drop_period = false
pause *= opt[:adjust]
end
sleep(pause)
}
}
}
}
end
There are more api-friendly libraries than Net::HTTP
, for example httparty:
require "httparty"
File.open("/tmp/my_file.flv", "wb") do |f|
f.write HTTParty.get("http://somedomain.net/flv/sample/sample.flv").parsed_response
end
I had problems, if the file contained German Umlauts (ä,ö,ü). I could solve the problem by using:
ec = Encoding::Converter.new('iso-8859-1', 'utf-8')
...
f << ec.convert(seg)
...
if you looking for a way how to download temporary file, do stuff and delete it try this gem https://github.com/equivalent/pull_tempfile
require 'pull_tempfile'
PullTempfile.transaction(url: 'https://mycompany.org/stupid-csv-report.csv', original_filename: 'dont-care.csv') do |tmp_file|
CSV.foreach(tmp_file.path) do |row|
# ....
end
end
참고URL : https://stackoverflow.com/questions/2263540/how-do-i-download-a-binary-file-over-http
'IT story' 카테고리의 다른 글
X-Powered-By 제거 (0) | 2020.07.03 |
---|---|
Facebook 숨기기 / 표시 확장 / 계약 탐색 모음 모방 (0) | 2020.07.03 |
GDB로 단일 중단 점을 어떻게 제거합니까? (0) | 2020.07.03 |
ggplot2에서 한계 히스토그램이있는 산점도 (0) | 2020.07.03 |
폭발에서 PHP 여러 구분 기호 (0) | 2020.07.03 |