Class: XlsxKit::ZipWriter
- Inherits:
-
Object
- Object
- XlsxKit::ZipWriter
- Defined in:
- lib/xlsxkit/zip_writer.rb
Overview
最小化 ZIP32 写入器,专为 XLSX 打包设计。
与 ZipReader 对应,不依赖 rubyzip,仅支持写入 XLSX 所需的两种压缩方式:
- DEFLATE (method 8): 通用压缩
- STORED (method 0): 无压缩
实现思路:
- add_entry 时即时写出 Local File Header + 数据,并记录偏移
- 同时在内存累积 Central Directory 记录
- close 时写出 Central Directory + EOCD 收尾
边写边压,避免将整个 ZIP 缓冲在内存或磁盘。
Constant Summary collapse
- LOCAL_SIG =
ZIP 格式签名
"PK\x03\x04".b.freeze
- CDENTRY_SIG =
Local File Header
"PK\x01\x02".b.freeze
- EOCD_SIG =
Central Directory File Header
"PK\x05\x06".b.freeze
- STORED =
压缩方法
0- DEFLATE =
8
Class Method Summary collapse
-
.open(path) ⇒ Object
便捷类方法:写入文件路径,块结束后自动收尾并关闭。.
Instance Method Summary collapse
-
#add_entry(name, data, method: DEFLATE) ⇒ Object
添加一个条目(文件),立即写出数据。.
-
#close ⇒ Object
写出 Central Directory 与 EOCD,收尾 ZIP 文件。.
-
#initialize(io) ⇒ ZipWriter
constructor
初始化写入器。.
Constructor Details
#initialize(io) ⇒ ZipWriter
初始化写入器。
49 50 51 52 53 54 |
# File 'lib/xlsxkit/zip_writer.rb', line 49 def initialize(io) @io = io @offset = 0 # 当前数据起始偏移(用于 Central Directory 定位) @count = 0 # 条目数 @central = ''.b # 中央目录累积缓冲 end |
Class Method Details
.open(path) ⇒ Object
便捷类方法:写入文件路径,块结束后自动收尾并关闭。
58 59 60 61 62 63 64 |
# File 'lib/xlsxkit/zip_writer.rb', line 58 def self.open(path) File.open(path, 'wb') do |f| writer = new(f) yield writer writer.close end end |
Instance Method Details
#add_entry(name, data, method: DEFLATE) ⇒ Object
添加一个条目(文件),立即写出数据。
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/xlsxkit/zip_writer.rb', line 72 def add_entry(name, data, method: DEFLATE) name_bytes = name.b data_bytes = data.b crc = Zlib.crc32(data_bytes) compressed = case method when STORED then data_bytes when DEFLATE then Zlib::Deflate.new(nil, -Zlib::MAX_WBITS).deflate(data_bytes, Zlib::FINISH) else raise ArgumentError, "unsupported compression method: #{method}" end # Local File Header (30 bytes + name + data) local = LOCAL_SIG.dup local << [20, 0, method, 0, 0, crc, compressed.bytesize, data_bytes.bytesize, name_bytes.bytesize, 0].pack('vvvvvVVVvv') local << name_bytes local << compressed @io.write(local) # Central Directory Record (46 bytes + name) cd = CDENTRY_SIG.dup cd << [20, 20, 0, method, 0, 0, crc, compressed.bytesize, data_bytes.bytesize, name_bytes.bytesize, 0, 0, 0, 0, 0, @offset].pack('vvvvvvVVVvvvvvVV') cd << name_bytes @central << cd @offset += local.bytesize @count += 1 self end |
#close ⇒ Object
写出 Central Directory 与 EOCD,收尾 ZIP 文件。
108 109 110 111 112 113 114 115 116 |
# File 'lib/xlsxkit/zip_writer.rb', line 108 def close cd_offset = @offset @io.write(@central) eocd = EOCD_SIG.dup eocd << [0, 0, @count, @count, @central.bytesize, cd_offset, 0].pack('vvvvVVv') @io.write(eocd) @io end |