//untar TAR格式解压 import zlib; import fsys; import fsys.file; import fsys.time; namespace fsys; class untar{ ctor( path,saveDir ){ var tarFile; if(type(path)!="string" && type(path.size) == "function"){ tarFile = path; if( ! (saveDir?..fsys.createDir(saveDir) ) ) return null,"错误的存储目录"; } else{ var path = ..io.exist(path); if(!path) return null,"错误的tar文件路径"; if(!saveDir)saveDir = ..string.match(path,"(.*\\\w+)\.[\w.]+$"); if( ! (saveDir?..fsys.createDir(saveDir) ) ) return null,"错误的存储目录"; if( ..string.match(path,"<.gz>|<.tgz>$") ){ tarFile = ..zlib.gzFile(path,"rb") } else { tarFile = ..io.file(path,"rb") } if(!tarFile) return null,"打开tar文件失败"; } { var size = tarFile.size(); if( size < 0 ) size = 0xFFFFFFFF; this.blocksCount = ( size / 512 ) - 1; if( this.blocksCount < 1 ) return null,"tar文件格式错误"; } var curFileName,curFile; var curFileSize = 0; var curFileTime = ..fsys.time() var tarHeader = tar_header(); var buffer = ..raw.buffer(512); this.utf8 = null; ..table.gc(this,"close"); }; nextBlock = function(){ if( curFileSize <= 0){ if( curFile ) curFile.close(); if( ! tarFile.read( tarHeader ) ){ return null,"读取TAR头失败"; } var name = ..string.str(tarHeader.name); if( !#name ){ this.complete = true; return;//last block } this.complete = false; if( this.utf8 === false ){ name = ..string.fromto(name,0,65001); } elseif( this.utf8 !== true ) { if( !..string.len(name) ){ name = ..string.fromto(name,0,65001); } } tarHeader.name = name; curFileName = ..io.joinpath(saveDir,name); curFileSize = tonumber(tarHeader.size,8) var linkflag = tarHeader.linkflag; var mtime = tonumber(tarHeader.mtime,8) curFileTime.fromSystemTime( ..time(mtime) ); if( linkflag == '5'#/*LF_DIR*/ ){ ..fsys.createDir(curFileName); if( this.onProgressFolder ){ this.onProgressFolder(name); } return curFileName,0; } if( this.onProgressFile ){ this.onProgressFile(name); } if( curFileSize == 0 ){ return curFileName,0; } ..fsys.createParentDir( curFileName ); curFile = ..fsys.file(curFileName,"w+b"); if(!curFile) return null,"写入文件失败:" + name; curFile.setFileTime( creation = curFileTime ;access = curFileTime ;write = curFileTime); return curFileName,0,curFileSize; } var writeSize = ..math.min(512,curFileSize ) tarFile.readBuffer(buffer,512); curFile.writeBuffer( buffer,writeSize ); curFileSize = curFileSize - writeSize; return curFileName,writeSize,curFileSize; } eachBlock = function(posRange){ if(!posRange) return this.nextBlock; var processed = 0; var step = this.blocksCount / posRange; var posOld,posNew; this.lastError = null; var nextBlock; nextBlock = function(){ var fileName,writeSize,remainSize = this.nextBlock(); if(fileName) { processed++; posNew = ..math.floor(processed / step); if( posNew != posOld ){ posOld = posNew return fileName,writeSize,remainSize,posNew } return nextBlock(); } else { this.lastError = writeSize; } } return nextBlock; } close = function(){ if( tarFile ){ tarFile.close(); tarFile = null; return this.complete; } } } namespace untar { class tar_header { byte name[100]; byte mode[8]; byte uid[8]; byte gid[8]; byte size[12]; byte mtime[12]; byte chksum[8]; byte linkflag; byte linkname[100]; byte magic[8]; byte uname[32]; byte gname[32]; byte devmajor[8]; byte devminor[8]; byte prefix[155]; byte data[12] } } /**intellisense() fsys.untar = tar文件操作 fsys.untar(.("tar文件路径",存储路径) = 参数@1可以是 *.tar, *.tar.gz, *.tgz 类型文件路径,\n参数 @1 也可以指定 fsys.stream 或 fsys.file,io.file 等文件对象,\n如果参数@1为文件路径,则参数@2为可选参数 fsys.untar() = !fsys_untarfile. !fsys_untarfile.utf8 = tar 文件名是否使用 UTF8 编码。\n设为 false ,表示文件名使用 ANSI 多字节编码。\n设为 true 表示文件名使用 utf8 编码,\n设为 null 则自动检测。\n目前 tar 文件一般使用 UTF-8 编码文件名,使用 ANSI 编码不常见。 !fsys_untarfile.blocksCount = 数据块总数,\n仅供进度条使用的估算值 !fsys_untarfile.onProgressFolder = @.onProgressFolder = function(path){ __/*正在创建目录*/ } !fsys_untarfile.onProgressFile = @.onProgressFile = function(path){ __/*正在创建文件*/ } !fsys_untarfile.nextBlock() = 释放下一个块,\n成功返回文件名,释放大小,\n同一文件可能需要释放多个文件块 !fsys_untarfile.eachBlock(posRange) = @for(fileName,writeSize,remainSize,pos in ??.eachBlock() ){ __/*循环展开所有文件块,\n文件块较多时指定posRange参数可以减少循环次数以优化性能\nposRange参数可选指定一个表示进度上限的数值,\n指定posRange参数则返回值pos表示当前进度*/ } !fsys_untarfile.close() = 关闭文件,\n如果解包完成返回true !fsys_untarfile.lastError = 调用eachBlock解包时,可使用lastError获取错误信息 !fsys_untarfile.complete = 所有文件是否解包完成 end intellisense**/