Class: XlsxKit::ZipReader
- Inherits:
-
Object
- Object
- XlsxKit::ZipReader
- Defined in:
- lib/xlsxkit/zip_reader.rb
Overview
最小化 ZIP32 读取器,专为 XLSX 解包设计。
不依赖 rubyzip 等第三方 gem,仅支持 XLSX 中出现的两种压缩方式:
- DEFLATE (method 8): 通用压缩
- STORED (method 0): 无压缩
实现思路:
- 从文件末尾反向搜索 EOCD (End of Central Directory) 签名
- 解析中央目录,获取所有条目的元数据与 Local Header 偏移
- 按需读取单个条目:定位 Local Header → 跳过头部 → Zlib::Inflate 解压
与全量解包不同,本 reader 仅按 name 读取单个条目,避免将整个 ZIP 展开到内存或磁盘。
Constant Summary collapse
- EOCD_SIG =
ZIP 格式签名(freeze 防止外部 << 修改)
"PK\x05\x06".b.freeze
- CDENTRY_SIG =
End of Central Directory
"PK\x01\x02".b.freeze
- LOCAL_SIG =
Central Directory File Header
"PK\x03\x04".b.freeze
- STORED =
压缩方法
0- DEFLATE =
8
Instance Attribute Summary collapse
-
#entries ⇒ Object
readonly
解析中央目录,返回 => entry 的 Hash。 entry 为包含 :name, :method, :compressed_size, :uncompressed_size, :local_offset 的 Hash。.
Class Method Summary collapse
-
.open(path) ⇒ Object
便捷类方法:打开文件并读取后关闭。.
Instance Method Summary collapse
-
#close ⇒ Object
关闭底层 IO(若由本类打开)。.
-
#initialize(io) ⇒ ZipReader
constructor
初始化 ZIP 读取器。.
-
#read_entry(name) ⇒ String?
读取指定条目的原始字节(已解压)。.
-
#read_entry_utf8(name) ⇒ Object
读取指定条目并强制 UTF-8 编码(用于 XML 文本)。.
Constructor Details
#initialize(io) ⇒ ZipReader
初始化 ZIP 读取器。
52 53 54 55 |
# File 'lib/xlsxkit/zip_reader.rb', line 52 def initialize(io) @io = io.is_a?(String) ? File.open(io, 'rb') : io @entries = nil end |
Instance Attribute Details
#entries ⇒ Object (readonly)
解析中央目录,返回 => entry 的 Hash。 entry 为包含 :name, :method, :compressed_size, :uncompressed_size, :local_offset 的 Hash。
75 76 77 |
# File 'lib/xlsxkit/zip_reader.rb', line 75 def entries @entries end |
Class Method Details
.open(path) ⇒ Object
便捷类方法:打开文件并读取后关闭。
59 60 61 62 63 64 |
# File 'lib/xlsxkit/zip_reader.rb', line 59 def self.open(path) reader = new(path) yield reader ensure reader&.close end |
Instance Method Details
#close ⇒ Object
关闭底层 IO(若由本类打开)。
68 69 70 |
# File 'lib/xlsxkit/zip_reader.rb', line 68 def close @io.close unless @io.closed? end |
#read_entry(name) ⇒ String?
读取指定条目的原始字节(已解压)。
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/xlsxkit/zip_reader.rb', line 119 def read_entry(name) entry = entries[name] return nil unless entry data_offset = resolve_data_offset(entry[:local_offset]) @io.seek(data_offset) raw = @io.read(entry[:compressed_size]) case entry[:method] when STORED raw when DEFLATE Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(raw) else raise "Unsupported compression method: #{entry[:method]}" end end |
#read_entry_utf8(name) ⇒ Object
读取指定条目并强制 UTF-8 编码(用于 XML 文本)。
139 140 141 142 143 |
# File 'lib/xlsxkit/zip_reader.rb', line 139 def read_entry_utf8(name) data = read_entry(name) return nil unless data data.force_encoding('UTF-8') end |