我知道如何使用rubyzip检索普通zip文件的内容。但是我在解压缩压缩文件夹的内容时遇到了麻烦,我希望你们中的任何人都能帮助我。
这是我用来解压缩的代码:
Zip::ZipFile::open(@file_location) do |zip|
zip.each do |entry|
next if entry.name =~ /__MACOSX/ or entry.name =~ /.DS_Store/ or !entry.file?
logger.debug "#{entry.name}"
@data = File.new("#{Rails.root.to_s}/tmp/#{entry.name}")
end
end
entry.name 给了我zip文件中文件的名称。这与普通的zip文件完美配合。但是当从文件夹创建zipfile时,条目的名称类似于:test-folder/test.pdf。当我尝试创建文件时,它告诉我找不到该文件。这可能是因为它位于 zip 内的"test"文件夹中。
如果我检查条目是否为文件夹,则找不到文件夹。所以我认为解决方案是将条目读取为流,然后将其另存为文件。获取入口流很容易,但是如何将其另存为文件?这就是我到目前为止得到的。
Zip::ZipFile::open(@file_location) do |zip|
zip.each do |entry|
next if entry.name =~ /__MACOSX/ or entry.name =~ /.DS_Store/ or !entry.file?
logger.debug "#{entry.name}"
@data = entry.get_input_stream.read
# How do i create a file from a stream?
end
end
基本上我的问题是:如何从流创建文件?还是有比我更容易的方法?
===编辑===我使用回形针来存储文件。
我发现基于 jhwist 的更简单的方法工作正常:
Zip::File.open(@file_location) do |zipfile|
zipfile.each do |entry|
# The 'next if...' code can go here, though I didn't use it
unless File.exist?(entry.name)
FileUtils::mkdir_p(File.dirname(entry.name))
zipfile.extract(entry, entry.name)
end
end
end
条件显然是可选的,但是如果没有它,如果代码尝试覆盖现有文件,它将引发错误。
我认为您的问题不在于是否需要从流中写入文件。 基本上,如果你调用File.new
它将创建一个新的IO流(File
是IO
的子类)。因此,无论您想对 zip 文件中的流做什么,也应该使用常规文件。
当你说
当我尝试创建文件时,它告诉我找不到该文件
我认为发生的事情是您要创建的文件的父目录不存在(在您的情况下是test-folder
)。你想做的是这样的(未经测试):
Zip::ZipFile::open(@file_location) do |zip|
zip.each do |entry|
next if entry.name =~ /__MACOSX/ or entry.name =~ /.DS_Store/ or !entry.file?
logger.debug "#{entry.name}"
FileUtils::mkdir_p(File.dirname(entry.name)) # might want to check if it already exists
@data = File.new("#{Rails.root.to_s}/tmp/#{entry.name}")
end
end
我通过使用流并创建一个 StringIO 来解决它。这是代码
Zip::ZipFile::open(@file_location) do |zip|
zip.each do |entry|
next if entry.name =~ /__MACOSX/ or entry.name =~ /.DS_Store/ or !entry.file?
begin
# the normal unzip-code
rescue Errno::ENOENT
# when the entry can not be found
@data = entry.get_input_stream.read
@file = StringIO.new(@data)
@file.class.class_eval { attr_accessor :original_filename, :content_type }
@file.original_filename = entry.name
@file.content_type = MIME::Types.type_for(entry.name)
# save it / whatever
end
end
end