如何直接从 ZipEntry(RubyZip、Paperclip、Rails 3)获取临时 File 对象(具有正确的内容类型,无需写入磁盘)?

发布于 2024-10-16 07:52:31 字数 1625 浏览 5 评论 0原文

我目前正在尝试直接从 zip 文件将图像文件附加到模型(即不先将它们保存在磁盘上)。似乎应该有一种更清晰的方法将 ZipEntry 转换为可以存储在内存中的临时文件或文件,以便传递给另一个知道如何处理它的方法或对象。

这是我的代码:

def extract (file = nil)
  Zip::ZipFile.open(file) { |zip_file|
    zip_file.each { |image|
      photo = self.photos.build
      # photo.image = image # this doesn't work
      # photo.image = File.open image # also doesn't work
      # photo.image = File.new image.filename
      photo.save
    }
  }
end

但问题是 photo.image 是模型的附件(通过回形针),并且将某些内容指定为附件需要该内容是 File 对象。但是,我一生都无法弄清楚如何将 ZipEntry 转换为文件。我见过的打开或创建文件的唯一方法是使用字符串作为其路径 - 这意味着我必须将文件提取到某个位置。真的,这看起来很愚蠢。为什么我不能将 ZipEntry 文件提取到输出流并将其转换为文件?

所以最终的问题是:我可以从 Zip 文件中提取 ZipEntry 并将其直接转换为 File 对象(或直接将其附加为 Paperclip 对象)吗?还是我在附加它之前实际上将其存储在硬盘驱动器上,即使该版本最终会被删除?

更新 感谢蓝莓田,我想我离我的解决方案更近了一些。这是我添加的代码行,它为我提供了所需的临时文件/文件:

photo.image = zip_file.get_output_stream image

但是,我的 Photo 对象不会接受正在传递的文件,因为它不是 图像/jpeg。事实上,检查文件的 content_type 显示 application/x-empty。我认为这可能是因为获取输出流似乎会在文件末尾附加一个时间戳,因此它最终看起来像 imagename.jpg20110203-20203-hukq0n编辑:此外,它创建的临时文件不包含任何数据,大小为 0。所以看起来这可能不是答案。

那么,下一个问题:有谁知道如何得到它来给我一个图像/jpeg 文件?

更新

我一直在尝试这个问题。看来输出流不是要走的路,而是输入流(这总是让我感到困惑)。在 ZipEntry 上使用 get_input_stream,我获取文件中的二进制数据。我想现在我只需要弄清楚如何将其放入回形针附件(作为文件对象)。我尝试过将 ZipInputStream 直接推送到附件,但是当然,这是行不通的。我真的很难相信没有人尝试将提取的 ZipEntry 转换为文件。是否有某种原因认为这会被认为是不好的编程实践?在我看来,跳过临时文件的磁盘写入是完全可以接受的,并且在 Zip 存档管理之类的东西中受到支持。

无论如何,问题仍然存在:

有没有办法将输入流转换为文件对象(或临时文件)?最好不必写入磁盘。

I'm currently trying to attach image files to a model directly from a zip file (i.e. without first saving them on a disk). It seems like there should be a clearer way of converting a ZipEntry to a Tempfile or File that can be stored in memory to be passed to another method or object that knows what to do with it.

Here's my code:

def extract (file = nil)
  Zip::ZipFile.open(file) { |zip_file|
    zip_file.each { |image|
      photo = self.photos.build
      # photo.image = image # this doesn't work
      # photo.image = File.open image # also doesn't work
      # photo.image = File.new image.filename
      photo.save
    }
  }
end

But the problem is that photo.image is an attachment (via paperclip) to the model, and assigning something as an attachment requires that something to be a File object. However, I cannot for the life of me figure out how to convert a ZipEntry to a File. The only way I've seen of opening or creating a File is to use a string to its path - meaning I have to extract the file to a location. Really, that just seems silly. Why can't I just extract the ZipEntry file to the output stream and convert it to a File there?

So the ultimate question: Can I extract a ZipEntry from a Zip file and turn it directly into a File object (or attach it directly as a Paperclip object)? Or am I stuck actually storing it on the hard drive before I can attach it, even though that version will be deleted in the end?

UPDATE
Thanks to blueberry fields, I think I'm a little closer to my solution. Here's the line of code that I added, and it gives me the Tempfile/File that I need:

photo.image = zip_file.get_output_stream image

However, my Photo object won't accept the file that's getting passed, since it's not an image/jpeg. In fact, checking the content_type of the file shows application/x-empty. I think this may be because getting the output stream seems to append a timestamp to the end of the file, so that it ends up looking like imagename.jpg20110203-20203-hukq0n. Edit: Also, the tempfile that it creates doesn't contain any data and is of size 0. So it's looking like this might not be the answer.

So, next question: does anyone know how to get this to give me an image/jpeg file?

UPDATE:

I've been playing around with this some more. It seems output stream is not the way to go, but rather an input stream (which is which has always kind of confused me). Using get_input_stream on the ZipEntry, I get the binary data in the file. I think now I just need to figure out how to get this into a Paperclip attachment (as a File object). I've tried pushing the ZipInputStream directly to the attachment, but of course, that doesn't work. I really find it hard to believe that no one has tried to cast an extracted ZipEntry as a File. Is there some reason that this would be considered bad programming practice? It seems to me like skipping the disk write for a temp file would be perfectly acceptable and supported in something like Zip archive management.

Anyway, the question still stands:

Is there a way of converting an Input Stream to a File object (or Tempfile)? Preferably without having to write to a disk.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

家住魔仙堡 2024-10-23 07:52:32

查看 ZipFile 上的 get_input_stream 和 get_output_stream 消息。

Check out the get_input_stream and get_output_stream messages on ZipFile.

风铃鹿 2024-10-23 07:52:31

试试这个

Zip::ZipFile.open(params[:avatar].path) do |zipfile|
  zipfile.each do |entry|
    filename = entry.name
    basename = File.basename(filename)

    tempfile = Tempfile.new(basename)
    tempfile.binmode
    tempfile.write entry.get_input_stream.read

    user = User.new
    user.avatar = {
      :tempfile => tempfile,
      :filename => filename
    }
    user.save

  end
end

Try this

Zip::ZipFile.open(params[:avatar].path) do |zipfile|
  zipfile.each do |entry|
    filename = entry.name
    basename = File.basename(filename)

    tempfile = Tempfile.new(basename)
    tempfile.binmode
    tempfile.write entry.get_input_stream.read

    user = User.new
    user.avatar = {
      :tempfile => tempfile,
      :filename => filename
    }
    user.save

  end
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文