Ruby - 如何使用open-uri获取文件的名称?

时间:2012-11-15 08:21:22

标签: ruby http url uri 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))

我认为这没有任何意义,但我不知道如何做到这一点,抱歉。

2 个答案:

答案 0 :(得分:15)

文件名存储在名为Content-Disposition的标题字段中。但是解码这个字段可能有点棘手。请参阅此处的一些讨论:

How to encode the filename parameter of Content-Disposition header in HTTP?

对于open-uri,您可以通过返回的File类的meta访问者访问所有标头字段:

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=(\"?)(.+)\1/)[2]
=> "Stereo Foo - Cohete Amigo.wav"

它适用于您的特定情况,如果引号"不存在,它也有效。但在更复杂的内容处理案例中,如UTF-8文件名,您可能会遇到一些麻烦。不确定UTF-8的使用频率,甚至是声音云还是使用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"

答案 1 :(得分:6)

File.basename(open(source_url))无效,因为open(source_url)会返回某种类型的I / O句柄,而不是File.basename期望的字符串。

File.basename(source_url)
除非URL使用某种path/to/service/with/parameters/in/line/like/this类型编码,否则

将有更好的工作机会。

Ruby的URI库提供了有用的工具来帮助解决这个问题。类似的东西:

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,并让gem为其文档启动一个小型Web服务器:

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提取完整的回复。