How to close a ZipFile

1.4k Views Asked by At

I'm passing a dynamic zip file location to a def from a database. I want to unzip the file to a temp location, extract the xml report file inside, apply an xslt stylesheet, copy it as an rhtml to a view directory for rendering, and delete the temp extracted xml file. The functionality is working fine (the rhtml file is overwritten each time and renders) except it is extracting from the same parent zip for each execution and the extracted xml can not be deleted which leads me to believe that the first execution is not closing the parent zip (releasing its handle). Therefore, subsequent executions are extracting the xml from the first zip executed. I've tried "Zip::ZipFile.close", "zipFile = Zip::ZipFile.open(fileLocation); zipFile.close","File.close(fileLocation)", and other permutations. Any help would be appreciated.

1

There are 1 best solutions below

4
On

Can you pass a block to Zip::ZipFile.open? This will close it when the block exits:

Zip::ZipFile.open(file_name) do |zip_file|
  zip_file.extract('report.xml', '/tmp')
end

# zip file is closed at this point
# apply_xslt
# copy rhtml to app/views/...
# etc

== EDIT ==

Based on your comments, here's a working example:

require 'rubygems'
require 'zip/zip'
require 'fileutils'

zip_file_name = 'test.zip'
out_dir = 'tmp_for_zip'
FileUtils.mkdir_p out_dir

Zip::ZipFile.open(zip_file_name) do |zip_file|
  report_name = File.basename(zip_file.name).gsub('zip', 'xml')
  out = File.join(out_dir, report_name)
  zip_file.extract(report_name, out) unless File.exists?(out)
  puts "extracted #{report_name} to #{out}"
end

Also, I don't know if you are running a unix, but you can use lsof (list open files) to find out if the file is actually open:

lsof | grep your_file_name