Ruby-как получить имя файла с open-uri?
Я хочу загрузить музыкальный файл следующим образом:
require 'open-uri'
source_url = "http://soundcloud.com/stereo-foo/cohete-amigo/download"
attachment_file = "test.wav"
open(attachment_file, "wb") do |file|
file.print open(source_url).read
end
в этом примере я хочу изменить " Test.wav " для реального имени файла (например, программа JDownloader).
редактировать: Я не имею в виду временной файл, я имею в виду сохраненный файл в интернете, как Jdownloader получает: "Cohete Amigo - Stereo Foo.WAV и"
Спасибо, что прочитала
обновление:
Я пробовал это, чтобы сохранить имя:
attachment_file = File.basename(open(source_url))
I думаю, в этом нет смысла, но я не знаю, как это сделать, извините.
2 ответов
имя файла хранится в поле с именем Content-Disposition
. Однако декодирование этого поля может быть немного сложным. См. некоторые обсуждения здесь, например:
как кодировать параметр filename заголовка Content-Disposition в HTTP?
на open-uri
вы можете получить доступ ко всем полям заголовка через meta
доступа возвращенных File
класс:
f = open('http://soundcloud.com/stereo-foo/cohete-amigo/download')
f.meta['content-disposition']
=> "attachment;filename=\"Stereo Foo - Cohete Amigo.wav\""
Итак, чтобы расшифровать что-то подобное, вы мог бы это сделать:
cd = f.meta['content-disposition'].
filename = cd.match(/filename=(\"?)(.+)/)[2]
=> "Stereo Foo - Cohete Amigo.wav"
он работает для вашего конкретного случая, и он также работает, если кавычки "
нет. Но в более сложных случаях размещения контента, таких как имена файлов UTF-8, вы можете попасть в небольшую неприятность. Не уверен, как часто UTF-8 используется, хотя, и если даже soundcloud когда-либо использует UTF-8. Так что, возможно, Вам не нужно беспокоиться об этом (не подтверждено и не проверено).
вы также можете использовать более продвинутую структуру веб-обхода, такую как Mechanize
, и доверьте ему сделать расшифровывать для вас:
require 'mechanize'
agent = Mechanize.new
file = agent.get('http://soundcloud.com/stereo-foo/cohete-amigo/download')
file.filename
=> "Stereo_Foo_-_Cohete_Amigo.wav"
File.basename(open(source_url))
не будет работать, потому что open(source_url)
возвращает дескриптор ввода-вывода, а не строку типа File.basename
ожидает.
File.basename(source_url)
было бы лучше работать, если URL-адрес не использует некоторые path/to/service/with/parameters/in/line/like/this
тип кодировки.
библиотека URI Ruby имеет полезные инструменты, чтобы помочь здесь. Что-то вроде:
File.basename(URI.parse(source_url).path)
будет отправной точкой. Например:
require 'uri'
File.basename(URI.parse('http://www.example.com/path/to/file/index.html').path
# => "index.html"
и:
File.basename(URI.parse('http://www.example.com/path/to/file/index.html?foo=bar').path)
# => "index.html"
вы знаю, если я могу извлечь файл и как?
отличный способ проверить http-материал локально-запустить gem server
из командной строки, и пусть драгоценные камни запускают небольшой веб-сервер для его документации:
require 'open-uri'
html_doc = open('http://0.0.0.0:8808/') do |io|
puts io.size
io.read
end
puts html_doc.size
# => 114350
# => 114350
когда вы используете блок с OpenURI в open
команда, она дает вам доступ к большому количеству информации о соединении в переменной блока, которая является экземпляром Tempfile
класса. Так, вы можете узнать размер входящего файла, используя size
.
это нормально для небольших файлов, но если вы вытаскиваете большой файл, который вы можете исследовать с помощью Net:: HTTP для отправки head
запрос, который может включить размер. Я говорю может, потому что иногда сервер не знает, сколько будет возвращено, в случае динамического контента или контента, возвращаемого CGI или субсервисом, который не потрудился сказать.
преимущество использования запроса "head" заключается в том, что сервер не возвращает весь контент, а только заголовки. Итак, в прошлом я предварял запрос, используя head
, чтобы посмотреть, смогу ли я получить необходимые мне данные. Если нет, я был бы вынужден вытащить полный ответ, используя нормальный get
.