在TCL中读取gzip文件时,tell函数返回-1如何获取当前位置?
解决Tcl中zlib解压流
tell返回-1的问题 当你通过zlib push gunzip给文件句柄添加解压过滤层后,这个句柄会变成不可查找的过滤流,Tcl中这类流的tell命令会固定返回-1,这是正常行为——因为过滤流是动态处理数据的,无法直接映射到原始文件的固定位置。
下面提供两种可行的位置追踪方案:
方案1:追踪解压后的字节位置
如果只需要知道解压后文本的当前位置,可以自己维护一个计数器,结合gets的返回值(读取的字节数,不含换行符)来累加:
set fp [open "foo.gz" r] zlib push gunzip $fp set uncompressed_pos 0 while {![eof $fp]} { set bytes_read [gets $fp line] if {$bytes_read >= 0} { # 加上换行符长度(Unix/Linux用1,Windows用2,根据实际环境调整) incr uncompressed_pos [expr {$bytes_read + 1}] puts "当前解压后位置: $uncompressed_pos" } else { # 处理最后一行无换行符的情况 if {[string length $line] > 0} { incr uncompressed_pos [string length $line] } } } close $fp
方案2:追踪原始压缩文件的读取位置
如果需要对应原始压缩文件的位置,由于gzip是流式压缩,无法精确映射单一行到压缩文件的字节位置,但可以通过分块读取解压的方式,追踪已读取的压缩文件字节数:
set fp [open "foo.gz" r] set decompressor [zlib create decompress] set compressed_pos 0 set buffer "" while {![eof $fp]} { # 分块读取压缩数据(4096字节可根据需求调整) set chunk [read $fp 4096] incr compressed_pos [string length $chunk] # 解压当前块 set uncompressed_chunk [$decompressor $chunk] append buffer $uncompressed_chunk # 从缓冲区中逐行提取内容 while {[set newline_idx [string first "\n" $buffer]] != -1} { set line [string range $buffer 0 $newline_idx] set buffer [string range $buffer [expr {$newline_idx + 1}] end] # 此处的compressed_pos是已读取的压缩文件字节数(近似对应当前行的压缩位置) puts "已读取压缩文件位置: $compressed_pos" } } # 处理缓冲区剩余的最后一行(无换行符) if {[string length $buffer] > 0} { puts "已读取压缩文件位置: $compressed_pos" } $decompressor finalize close $fp
注意:方案2得到的是压缩文件中已被读取的位置,而非当前行对应的精确压缩起始位置——gzip的流式特性决定了无法直接做这种精确映射,除非手动解析gzip的块结构,这会大幅增加复杂度。
内容的提问来源于stack exchange,提问作者kavi
相关产品推荐
相关产品推荐

