| 关键词: bytes 文件 长度 数据 源文件 目录 磁盘 尺寸 标记 不定 |
要实现对ZIP文件的解析,首先我们需要来了解一下ZIP文件的数据结构。简单的说,一个 ZIP 文件的普通格式由三个部分组成: 压缩源文件数据区+压缩源文件目录区+压缩源文件目录结束标志。1、压缩源文件数据区在这个数据区中每一个压缩的源文件/目录都是一条记录,记录的格式如下:[文件头+ 文件数据 + 数据描述符]a、文件头结构组成 长度文件头标记 4 bytes (0×04034b50)解压文件所需 pkware 版本 2 bytes全局方式位标记 2 bytes压缩方式 2 bytes最后修改文件时间 2 bytes最后修改文件日期 2 bytesCRC-32校验 4 bytes压缩后尺寸 4 bytes未压缩尺寸 4 bytes文件名长度 2 bytes扩展记录长度 2 bytes文件名 (不定长度)扩展字段 (不定长度)b、文件数据c、数据描述符组成 长度CRC-32校验 4 bytes压缩后尺寸 4 bytes未压缩尺寸 4 bytes这个数据描述符只在全局方式位标记的第3位设为1时才存在(见后详解),紧接在压缩数据的最后一个字节后。这个数据描述符只用在不能对输出的 ZIP 文件进行检索时使用。例如:在一个不能检索的驱动器(如:磁带机上)上的 ZIP 文件中。如果是磁盘上的ZIP文件一般没有这个数据描述符。2、压缩源文件目录区在这个数据区中每一条纪录对应在压缩源文件数据区中的一条数据组成 长度目录中文件文件头标记 4 bytes (0×02014b50)压缩使用的 pkware 版本 2 bytes解压文件所需 pkware 版本 2 bytes全局方式位标记 2 bytes压缩方式 2 bytes 10最后修改文件时间 2 bytes 12最后修改文件日期 2 bytes 14CRC-32校验 4 bytes 18压缩后尺寸 4 bytes 22未压缩尺寸 4 bytes 26文件名长度 2 bytes 28扩展字段长度 2 bytes 30文件注释长度 2 bytes 32磁盘开始号 2 bytes 34内部文件属性 2 bytes 36外部文件属性 4 bytes 38局部头部偏移量 4 bytes 42文件名 (不定长度) 46扩展字段 (不定长度)文件注释 (不定长度)3、压缩源文件目录结束标志组成 长度目录结束标记 4 bytes (0×06054b50)当前磁盘编号 2 bytes 4目录区开始磁盘编号 2 bytes 6本磁盘上纪录总数 2 bytes 8目录区中纪录总数 2 bytes 10目录区尺寸大小 4 bytes 12目录区对第一张磁盘的偏移量 4 bytes 16ZIP 文件注释长度 2 bytes 20ZIP 文件注释 (不定长度)下面是实现代码: 复制内容到剪贴板 程序代码 <?xml version="1.0" encoding="utf-8"?> <mx:Window xmlns:mx="http://www.adobe.com/2006/mxml" title="分析ZIP文件" layout="vertical" width="500" height="300" creationComplete="init();"> <mx:Script> <![CDATA[ import flash.filesystem.*; import flash.utils.ByteArray; import flash.events.Event; private var bytes:ByteArray = new ByteArray(); //定义用来存储文件标头中元数据的变量 variables for reading fixed portion of file header private var fileName:String = new String(); private var flNameLength:uint; private var xfldLength:uint; private var offset:uint; private var compSize:uint; private var uncompSize:uint; private var compMethod:int; private var signature:int; private var k:int; //定义用来表示 .zip 文件的 File (zfile) 和 FileStream (zStream) 对象,并指定将从中提取文件的 .zip 文件的位置(桌面目录 //下名为“HelloAIR.zip” 的文件)。 // File variables for accessing .zip file private var zfile:File = File.desktopDirectory.resolvePath("HelloAIR.zip"); private var zStream:FileStream = new FileStream(); private function init():void { var screenBounds:Rectangle = Screen.mainScreen.bounds; nativeWindow.x = (screenBounds.width - nativeWindow.width) / 2; nativeWindow.y = (screenBounds.height - nativeWindow.height) / 2; } private function readout():void { zStream.open(zfile, FileMode.READ); bytes.endian = Endian.LITTLE_ENDIAN; while (zStream.position < zfile.size) { //前 30 个字节组成了第一个文件标头的固定大小部分。 // read fixed metadata portion of local file header zStream.readBytes(bytes, 0, 30); bytes.position = 0; signature = bytes.readInt(); // 再没有可提取的文件, quit if (signature != 0x04034b50)//文件开始标记 { break; } bytes.position = 8; compMethod = bytes.readByte(); // store compression method (8 == Deflate)压缩算法 通常是8,没压缩的是0 offset = 0;// stores length of variable portion of metadata bytes.position = 26; // offset to file name length flNameLength = bytes.readShort();// store file name trace("flNameLength="+flNameLength); offset += flNameLength; // add length of file name bytes.position = 28;// offset to extra field length xfldLength = bytes.readShort(); trace("xfldLength="+xfldLength); offset += xfldLength;// add length of extra field // 接下来程序将读取文件标头的可变长度部分,以将该部分的字节数存储在 offset 变量中。 zStream.readBytes(bytes, 30, offset); bytes.position = 30; fileName = bytes.readMultiByte(flNameLength,"gbk"); // read file name taFiles.text += fileName + "\n"; // write file name to text area bytes.position = 18; compSize = bytes.readUnsignedInt(); // store size of compressed portion taFiles.text += "\tCompressed size is: " + compSize + '\n'; bytes.position = 22; // offset to uncompressed size uncompSize = bytes.readUnsignedInt(); // store uncompressed size taFiles.text += "\tUncompressed size is: " + uncompSize + '\n'; //将文件的其余部分按照压缩后大小所指定的长度读入 ,未压缩的长度会等于压缩的,所以长度是对的 zStream.readBytes(bytes, 0, compSize); if (compMethod == 8) // if file is compressed, uncompress { bytes.uncompress(CompressionAlgorithm.DEFLATE); } outFile(fileName, bytes); } // end of while loop var flen:int=0; var externlen:int=0; var showlen:int=0; while (zStream.position < zfile.size)//目录开始标记为0x02014b50 { if(signature != 0x02014b50) break; bytes.position = 10; compMethod = bytes.readByte(); bytes.position = 28; flen= bytes.readByte(); trace("bytes.path len:"+flen); zStream.readBytes(bytes, 0, 46-30); bytes.position = 0; externlen=bytes.readByte(); trace("bytes.externlen len:"+externlen); bytes.position = 2; showlen=bytes.readByte(); trace("bytes.showlen len:"+showlen); zStream.readBytes(bytes, 0, flen+externlen+showlen); if((zStream.position+30)<zfile.size){ zStream.readBytes(bytes, 0, 30); bytes.position = 0; signature = bytes.readInt(); }else{ break; } } zStream.readBytes(bytes, 0, 22); bytes.position = 0; signature = bytes.readInt(); if(signature == 0x06054b50){//目录结束标志 bytes.position = 20; showlen=bytes.readByte(); trace("bytes.show len="+showlen); zStream.readBytes(bytes, 22, showlen); bytes.position = 22; fileName=bytes.readMultiByte(showlen,"gbk"); taFiles.text+="\n注释:"+fileName; } } // end of init() method private function outFile(fileName:String, data:ByteArray):void { var outFile:File = File.desktopDirectory; // dest folder is desktop outFile = outFile.resolvePath(fileName); // name of file to write var outStream:FileStream = new FileStream(); // open output file stream in WRITE mode outStream.open(outFile, FileMode.WRITE); // write out the file outStream.writeBytes(data, 0, data.length); // close it outStream.close(); } private function selectTextFile(root:File):void { taFiles.text=""; var txtFilter:FileFilter = new FileFilter("Zip", "*.Zip;*.zip"); root.browseForOpen("Open", [txtFilter]); root.addEventListener(Event.Select, fileSelected); } private function fileSelected(event:Event):void { msg.text="读文件:"+event.target.nativePath; } // The application code goes here ]]> </mx:Script> <mx:Label id="msg" text="只是测试了不包含子目录的几个文件压缩的zip"/><mx:Button label="文件" click="selectTextFile(zfile)" /> <mx:TextArea id="taFiles" width="320" height="150"/> <mx:Button label="分析" click="readout()" /> </mx:Window> |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|