如何在Ruby on Rails中解压文件?

56

我正在使用 Ruby on Rails 将文件上传到服务器。

通常情况下,这是一个文本文件,我会将其保存在 Submission ActiveRecord 中的“file”字段中,并与其他字段(例如提交标题等)一起保存。

但是,用户也可以提交压缩文件。在这种情况下,应该解压缩 zipfile 并为 zip 中的每个文件创建一个新的 Submission,其中包含相同的文本字段,但是有当前文件。

我该怎么做呢?

我查看了网上的解压示例,但大多数都使用目录将文件解压缩。我不确定是否需要这样做,因为在 SubmissionsController 的当前 create 方法中,接收到一个文件对象,我认为当 Submission 保存方法被调用时,会自动生成保存文件的路径。所以我想也许我应该在内存中解压 zipfile,以获得文件对象数组,然后使用每个文件对象创建一个新的 Submission,但是使用相同的字段,并让 ActiveRecord 在将它们保存到数据库时为每个字段生成文件路径。 我可能错了,因为我对 Rails 和 Ruby 还比较新。

4个回答

49

我会使用 rubyzip gem。特别是其中的这部分:https://github.com/rubyzip/rubyzip/blob/master/lib/zip/filesystem.rb

它在内存中创建了一个人工文件系统,反映了压缩文件的内容。下面是一个基于文档示例的实例:

Rubyzip接口已更改!!! 不需要执行require "zip/zip",类名中的Zip前缀已被删除。

require 'zip'

Zip::File.open("my.zip") do |zipfile|
  zipfile.each do |file|
    # do something with file
  end
end

在你的情况下,只需将已上传临时文件的名称放在示例中的 my.zip 处,然后您可以循环遍历文件内容并对其进行常规操作。


我明白了,那么我该如何从zip文件中获取文件对象数组呢? - siamii
@bizso09,我刚刚更新了代码,展示了如何循环遍历内容。这里还有一个简单的教程,详细解释了:http://www.markhneedham.com/blog/2008/10/02/ruby-unzipping-a-file-using-rubyzip/。 - Ben Lee
很不幸,file 是 ZipEntry 类型而不是 File 类型,所以我无法使用 Submissions 保存它。 - siamii
2
@bizso09,请查看文档和示例。您可以从ZipFile中提取文件,例如zip_file.extract(f, f_path) unless File.exist?(f_path) - Ben Lee

27

来自RubyZip项目页面:

Rubyzip接口已更改!!!无需执行“require”zip/zip”和删除类名中的Zip前缀。

因此,@ben-lee的示例代码应更新为以下内容:

require 'zip'

Zip::File.open("my.zip") do |zipfile|
  zipfile.each do |file|
    # do something with file
  end
end

27

在Ruby中提取Zip文件

一旦您安装了rubyzip gem,您可以使用此方法来提取Zip文件:

require 'zip'

def extract_zip(file, destination)
  FileUtils.mkdir_p(destination)

  Zip::File.open(file) do |zip_file|
    zip_file.each do |f|
      fpath = File.join(destination, f.name)
      zip_file.extract(f, fpath) unless File.exist?(fpath)
    end
  end
end

你可以这样使用它:

extract_zip(zip_path, extract_destination)

我不知道它最近是否被更改过,但是 extract 方法只接受一个参数,如果你给它两个参数,它会抛出一个错误。 - kingsfoil
unless File.exist?(fpath) 这个条件的原因是什么?这只是为了复制其他工具的行为吗? - Jon Burgess
2
@JonBurgess 看起来是为了避免用相同的名称替换现有文件。 - Akash Agarwal

4

对我起作用:

gem install rubyzip

main.rb

require 'zip'

def extract_zip(file, destination)
  FileUtils.mkdir_p(destination)

  Zip::File.open(file) do |zip_file|
    zip_file.each do |f|
      fpath = File.join(destination, f.name)
      FileUtils.mkdir_p(File.dirname(fpath))
      zip_file.extract(f, fpath) unless File.exist?(fpath)
    end
  end
end

extract_zip('file.zip', 'tmp')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接