2012-11-15 35 views
8

我想通过这种方式来下载音乐文件: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阿米戈 - 立体声Foo.wav”

三江源阅读

UPDATE :

我试过这个存储的名称:

attachment_file = File.basename(open(source_url)) 

我认为没有意义,但我不认识路要做到这一点,对不起。

回答

15

文件名存储在名为Content-Disposition的标题字段中。然而解码这个领域可能有点棘手。看到一些讨论,在此例如:

How to encode the filename parameter of Content-Disposition header in 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=(\"?)(.+)\1/)[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" 
+0

谢谢,你知道我是否可以检索文件大小,而不必等待获取文件的所有MB? – ElektroStudios

+0

查看内容长度标题。 – Danyel

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" 

你知道,如果我能retreive文件大小也和怎么样?

一个伟大的方式在本地测试HTTP的东西,是运行在命令行gem server,让宝石启动一个小的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找出传入文件的大小。

这对小文件OK,但如果你是在一个大的文件拉着你可能要使用的Net :: HTTP发送head请求,这可能包括大小进行调查。我说可能是,因为有时服务器不知道在动态内容的情况下会返回多少内容,或者CGI或子服务返回的内容无需说明。

使用“头部”请求的好处是服务器不返回整个内容,只是头部。所以,在过去,我已经使用head作为前言发出请求,以查看我是否可以获取所需的数据。如果不是的话,我会被迫使用正常的get来完整回复。

+0

谢谢,你知道我是否可以检索文件大小,以及如何? – ElektroStudios

+0

文件大小更难。它通常从服务器返回的HTTP头中返回,并且可以通过Net :: HTTP的方法访问。如果您使用带有“open”的块,其中一些可以在OpenURI的头文件中找到。问题是,并非所有的请求都会导致Content-Length头,因为服务器不知道会返回多少。对于由某种类型的CGI生成的动态内容尤其如此。 –

+0

感谢您的信息 – ElektroStudios

相关问题