我尝试编写一些邮件合并代码,我打开一个docx
文件(作为zip)用数据替换标签,然后创建一个新的docx
文件(作为zip)并迭代旧的zip文件,添加新的替换数据或从旧的docx
文件中提取现有文件,然后添加它。
我遇到的问题是,当我尝试访问out.get_output_stream
方法时,我收到以下错误:
cannot open entry for reading while its open for writing - [Content_Types].xml (StandardError)
[Content_Types].xml
恰好是docx
中的第一个文件,这就是为什么它会对该特定文件进行轰炸的原因。我做错了什么?
require 'rubygems'
require 'zip' # rubyzip gem
class WordMailMerge
def self.open(path, &block)
self.new(path, &block)
end
def initialize(path, &block)
@replace = {}
if block_given?
@zip = Zip::File.open(path)
yield(self)
@zip.close
else
@zip = Zip::File.open(path)
end
end
def force_settings
@replace["word/settings.xml"] = %{<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:settings xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main"><w:zoom w:percent="100"/></w:settings>}
end
def merge(rec)
xml = @zip.read("word/document.xml")
# replace tags with correct content
@replace["word/document.xml"] = xml
end
def save(path)
Zip::File.open(path, Zip::File::CREATE) do |out|
@zip.each do |entry|
if @replace[entry.name]
# this line creates the error
out.get_output_stream(entry.name).write(@replace[entry.name])
else
# this line also will do it.
out.get_output_stream(entry.name).write(@zip.read(entry.name))
end
end
end
end
def close
@zip.close
end
end
w = WordMailMerge.open("Option_2.docx")
w.force_settings
w.merge({})
w.save("Option_2_new.docx")
以下是堆栈跟踪:
/home/aaron/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/delegate.rb:85:in `call': cannot open entry for reading while its open for writing - [Content_Types].xml (StandardError)
from /home/aaron/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/delegate.rb:85:in `method_missing'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/streamable_stream.rb:28:in `get_input_stream'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/streamable_stream.rb:45:in `write_to_zip_output_stream'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/file.rb:313:in `block (3 levels) in commit'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/entry_set.rb:38:in `block in each'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/entry_set.rb:37:in `each'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/entry_set.rb:37:in `each'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/file.rb:312:in `block (2 levels) in commit'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/output_stream.rb:53:in `open'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/file.rb:311:in `block in commit'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/file.rb:409:in `block in on_success_replace'
from /home/aaron/.rvm/rubies/ruby-2.4.1/lib/ruby/2.4.0/tmpdir.rb:130:in `create'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/file.rb:407:in `on_success_replace'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/file.rb:310:in `commit'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/file.rb:334:in `close'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/file.rb:103:in `ensure in open'
from /home/aaron/.rvm/gems/ruby-2.4.1@appt/gems/rubyzip-1.2.1/lib/zip/file.rb:103:in `open'
from zip.rb:34:in `save'
from zip.rb:56:in `<main>'
答案 0 :(得分:1)
您需要将更新代码更改为
def save(path)
Zip::File.open(path, Zip::File::CREATE) do |out|
@zip.each do |entry|
if @replace[entry.name]
# this line creates the error
out.get_output_stream(entry.name){ |f| f.puts @replace[entry.name] }
else
# this line also will do it.
# out.get_output_stream(entry.name).write(@zip.read(entry.name))
out.get_output_stream(entry.name){ |f| f.puts @zip.read(entry.name) }
end
end
end
end
然后文件将被创建
修改-1 强>
以下是我用于测试的最终代码
require 'rubygems'
require 'zip' # rubyzip gem
class WordMailMerge
def self.open(path, &block)
self.new(path, &block)
end
def initialize(path, &block)
@replace = {}
if block_given?
@zip = Zip::File.open(path)
yield(self)
@zip.close
else
@zip = Zip::File.open(path)
end
end
def force_settings
@replace["word/settings.xml"] = %{<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:settings xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main"><w:zoom w:percent="100"/></w:settings>}
end
def merge(rec)
xml = @zip.read("word/document.xml")
# replace tags with correct content
@replace["word/document.xml"] = xml.gsub("{name}", "Tarun lalwani")
end
def save(path)
Zip::File.open(path, Zip::File::CREATE) do |out|
@zip.each do |entry|
if @replace[entry.name]
# this line creates the error
out.get_output_stream(entry.name){ |f| f.puts @replace[entry.name] }
else
# this line also will do it.
# out.get_output_stream(entry.name).write(@zip.read(entry.name))
out.get_output_stream(entry.name){ |f| f.puts @zip.read(entry.name) }
end
end
end
end
def close
@zip.close
end
end
w = WordMailMerge.open("Option_2.docx")
w.force_settings
w.merge({})
w.save("Option_2_new.docx")
<强> Option_2.docx 强>
<强> Option_2_new.doc 强>