Ruby 文件 IO:无法打开 url 作为文件对象
Ruby File IO: Can't open url as File object
我的代码中有一个函数,它接受一个表示图像 url 的字符串,并从该字符串创建一个 File
对象,以附加到推文。这似乎在大约 90% 的时间都有效,但偶尔会失败。
require 'open-uri'
attachment_url = "https://s3.amazonaws.com/FirmPlay/photos/images/000/002/443/medium/applying_too_many_jobs_-_daniel.jpg?1448392757"
image = File.new(open(attachment_url))
如果我运行上面的代码它returnsTypeError: no implicit conversion of StringIO into String
。如果我将 open(attachment_url)
更改为 open(attachment_url).read
,我会得到 ArgumentError: string contains null byte
。我也试过像这样从文件中删除空字节,但这也没有什么区别。
image = File.new(open(attachment_url).read.gsub("\u0000", ''))
现在,如果我用不同的图像尝试原始代码,例如下面的图像,它工作正常。它 returns 一个 File
预期的对象:
attachment_url = "https://s3.amazonaws.com/FirmPlay/photos/images/000/002/157/medium/mike_4.jpg"
我想这可能与原始 url 中的参数有关,所以我将其删除,但没有任何区别。如果我打开 Chrome 中的图像,它们似乎没问题。
我不确定我在这里遗漏了什么。我该如何解决这个问题?
谢谢!
更新
这是我的应用程序中的工作代码:
filename = self.attachment_url.split(/[\/]/)[-1].split('?')[0]
stream = open(self.attachment_url)
image = File.open(filename, 'w+b') do |file|
stream.respond_to?(:read) ? IO.copy_stream(stream, file) : file.write(stream)
open(file)
end
Jordan 的答案有效,除了调用 File.new
returns 一个空的 File
对象,而 File.open
returns 一个 File
对象包含图片数据来自 stream
.
你得到 TypeError: no implicit conversion of StringIO into String
的原因是 open
有时 returns 一个 String 对象,有时 returns 一个 StringIO 对象,这是不幸和令人困惑的。它的作用取决于文件的大小。有关详细信息,请参阅此答案:open-uri returning ASCII-8BIT from webpage encoded in iso-8859(尽管我不建议使用其中提到的确保编码 gem,因为它自 2010 年以来一直没有更新,并且 Ruby 具有重要意义从那时起与编码相关的变化。)
你得到 ArgumentError: string contains null byte
的原因是你试图将图像数据作为第一个参数传递给 File.new
:
image = File.new(open(attachment_url))
File.new
的第一个参数应该是文件名,大多数系统的文件名中不允许空字节。试试这个:
image_data = open(attachment_url)
filename = 'some-filename.jpg'
File.new(filename, 'wb') do |file|
if image_data.respond_to?(:read)
IO.copy_stream(image_data, file)
else
file.write(image_data)
end
end
以上打开文件(如果文件不存在就创建它;'wb'
中的b
告诉Ruby你要写入二进制数据),然后如果它是 StreamIO 对象,则使用 IO.copy_stream
将来自 image_data
的数据写入其中,否则使用 File#write
,然后再次关闭文件。
如果您使用 Paperclip,他们有一种方法可以复制到磁盘。
def raw_image_data
attachment.copy_to_local_file.read
end
将附件更改为您当然使用过的变量。
我的代码中有一个函数,它接受一个表示图像 url 的字符串,并从该字符串创建一个 File
对象,以附加到推文。这似乎在大约 90% 的时间都有效,但偶尔会失败。
require 'open-uri'
attachment_url = "https://s3.amazonaws.com/FirmPlay/photos/images/000/002/443/medium/applying_too_many_jobs_-_daniel.jpg?1448392757"
image = File.new(open(attachment_url))
如果我运行上面的代码它returnsTypeError: no implicit conversion of StringIO into String
。如果我将 open(attachment_url)
更改为 open(attachment_url).read
,我会得到 ArgumentError: string contains null byte
。我也试过像这样从文件中删除空字节,但这也没有什么区别。
image = File.new(open(attachment_url).read.gsub("\u0000", ''))
现在,如果我用不同的图像尝试原始代码,例如下面的图像,它工作正常。它 returns 一个 File
预期的对象:
attachment_url = "https://s3.amazonaws.com/FirmPlay/photos/images/000/002/157/medium/mike_4.jpg"
我想这可能与原始 url 中的参数有关,所以我将其删除,但没有任何区别。如果我打开 Chrome 中的图像,它们似乎没问题。
我不确定我在这里遗漏了什么。我该如何解决这个问题?
谢谢!
更新
这是我的应用程序中的工作代码:
filename = self.attachment_url.split(/[\/]/)[-1].split('?')[0]
stream = open(self.attachment_url)
image = File.open(filename, 'w+b') do |file|
stream.respond_to?(:read) ? IO.copy_stream(stream, file) : file.write(stream)
open(file)
end
Jordan 的答案有效,除了调用 File.new
returns 一个空的 File
对象,而 File.open
returns 一个 File
对象包含图片数据来自 stream
.
你得到 TypeError: no implicit conversion of StringIO into String
的原因是 open
有时 returns 一个 String 对象,有时 returns 一个 StringIO 对象,这是不幸和令人困惑的。它的作用取决于文件的大小。有关详细信息,请参阅此答案:open-uri returning ASCII-8BIT from webpage encoded in iso-8859(尽管我不建议使用其中提到的确保编码 gem,因为它自 2010 年以来一直没有更新,并且 Ruby 具有重要意义从那时起与编码相关的变化。)
你得到 ArgumentError: string contains null byte
的原因是你试图将图像数据作为第一个参数传递给 File.new
:
image = File.new(open(attachment_url))
File.new
的第一个参数应该是文件名,大多数系统的文件名中不允许空字节。试试这个:
image_data = open(attachment_url)
filename = 'some-filename.jpg'
File.new(filename, 'wb') do |file|
if image_data.respond_to?(:read)
IO.copy_stream(image_data, file)
else
file.write(image_data)
end
end
以上打开文件(如果文件不存在就创建它;'wb'
中的b
告诉Ruby你要写入二进制数据),然后如果它是 StreamIO 对象,则使用 IO.copy_stream
将来自 image_data
的数据写入其中,否则使用 File#write
,然后再次关闭文件。
如果您使用 Paperclip,他们有一种方法可以复制到磁盘。
def raw_image_data
attachment.copy_to_local_file.read
end
将附件更改为您当然使用过的变量。