programing

HTTP를 통해 이진 파일을 다운로드하려면 어떻게 해야 합니까?

golfzon 2023. 6. 3. 13:06
반응형

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

반응형