HTTP를 통해 이진 파일을 다운로드하려면 어떻게 해야 합니까?
루비를 사용하여 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."
편집: 변경됨.감사해요.
Edit2: 다운로드하는 동안 파일의 일부를 저장하는 솔루션:
# 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
저는 이것이 오래된 질문이라는 것을 알지만, 구글은 저를 여기에 던졌고 저는 더 간단한 답을 찾은 것 같습니다.
Railcasts #179에서 Ryan Bates는 Ruby 표준 클래스 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 to file 입니다.
require "open-uri"
require "fileutils"
def download(url, path)
case io = open(url)
when StringIO then File.open(path, 'w') { |f| f.write(io.read) }
when Tempfile then io.close; FileUtils.mv(io.path, path)
end
end
여기서의 주요 장점은 간결하고 단순합니다, 왜냐하면open무거운 물건을 들어올리는 일을 많이 합니다.그리고 그것은 기억 속의 전체 반응을 읽지 않습니다.
그open메소드는 응답을 1kb 이상으로 스트리밍합니다.Tempfile우리는 이 지식을 이용하여 이 파일로의 희박 다운로드 방법을 구현할 수 있습니다.여기에서 구현을 참조하십시오.
사용자가 제공한 입력에 주의하십시오!는 안전하지 않습니다.name사용자 입력에서 나옵니다!
사용하다OpenURI::open_uri디스크에서 파일을 읽지 않으려면:
...
case io = OpenURI::open_uri(url)
...
Ruby's net/http 문서의 예 3은 HTTP를 통해 문서를 다운로드하는 방법을 보여주며, 파일을 메모리에 로드하는 대신 파일에 이진 쓰기로 대체합니다. 예를 들어 Dejw의 답변에 나와 있습니다.
더 복잡한 사례는 동일한 문서 아래에 자세히 나와 있습니다.
다음 솔루션은 디스크에 쓰기 전에 먼저 전체 콘텐츠를 메모리에 읽습니다(더 효율적인 솔루션을 보려면 다른 답변을 참조하십시오).
원 라이너인 오픈우리를 이용하실 수 있습니다.
require 'open-uri'
content = open('http://example.com').read
또는 net/http를 사용하여
require 'net/http'
File.write("file_name", Net::HTTP.get(URI.parse("http://url.com")))
Dejw의 답변에 대한 확장(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
}
}
}
}
어디에filename그리고.url문자열입니다.
그sleep명령은 네트워크가 제한 요인일 때 CPU 사용량을 크게 줄일 수 있는 해킹입니다.Net::HTTP는 버퍼(v1.9.2의 16kB)가 채워질 때까지 기다리지 않으므로 CPU는 자체적으로 작은 청크를 이동합니다.잠시 자는 것은 버퍼가 쓰기 사이를 채울 수 있는 기회를 제공하며 CPU 사용량은 컬 솔루션과 맞먹으며 애플리케이션의 4-5배 차이가 납니다.보다 강력한 솔루션은 다음과 같은 작업의 진행 상황을 조사할 수 있습니다.f.pos시간 초과를 버퍼 크기의 95%를 대상으로 조정합니다. 실제로 제 예에서는 0.005라는 숫자를 얻었습니다.
미안하지만 루비가 버퍼가 채워질 때까지 기다리는 이보다 더 우아한 방법은 모르겠습니다.
편집:
이 버전은 자동으로 조정되어 버퍼 용량을 그대로 유지합니다.세련되지 않은 솔루션이지만, 컬링을 요구하는 만큼 CPU 시간을 적게 사용하고 빠릅니다.
그것은 3단계로 작동합니다.의도적으로 긴 수면 시간을 가진 짧은 학습 기간은 전체 버퍼의 크기를 결정합니다.삭제 기간은 채워지지 않은 버퍼를 찾을 때까지 각 반복마다 더 큰 요인을 곱하여 절전 시간을 빠르게 줄입니다.그런 다음 정상 기간 동안에는 더 작은 요인에 의해 위아래로 조정됩니다.
제 루비가 녹슬어서 개선할 수 있을 것 같아요.우선 오류 처리가 없습니다.또한 다운로드 자체에서 벗어나 객체로 분리되어 전화를 걸 수도 있습니다.autosleep.sleep(f.pos)당신의 루프에? 좋은은 Net가 양보하기 될 수 것입니다 :) Net: HTTP는 양보합니다.
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
보다 더 많은 api 친화적인 도서관들이 있습니다.Net::HTTP예: 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
파일에 독일어 Umlauts(ä,ö,ü)가 포함되어 있으면 문제가 있었습니다.다음을 사용하여 문제를 해결할 수 있었습니다.
ec = Encoding::Converter.new('iso-8859-1', 'utf-8')
...
f << ec.convert(seg)
...
만약 당신이 임시 파일을 다운로드하는 방법을 찾고 있다면, 무언가를 하고 그것을 삭제하세요. 이 보석 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
'programing' 카테고리의 다른 글
| Objective-C / Cocoa Touch에서의 HTML 문자 디코딩 (0) | 2023.06.03 |
|---|---|
| SQL Server 테이블 간에 행을 복사하는 방법 (0) | 2023.06.03 |
| 모든 Git 푸시에서 사용자 이름과 암호 지정을 방지하려면 어떻게 해야 합니까? (0) | 2023.06.03 |
| Postgre의 형식은 무엇입니까?SQL 연결 문자열 / URL? (0) | 2023.06.03 |
| 중첩 배열의 MongoDB 투영 (0) | 2023.06.03 |