private void pack(string filepath, string output) { if (Directory.Exists(filepath)) //要是一个存在的目录 { DirectoryInfo info = new DirectoryInfo(filepath); if ((output == null) || (output.Trim().Length == 0)) { output = info.FullName + ".tsk"; //目录名加.tsk为输出文件名 } FileStream stream = new FileStream(output, FileMode.Create); byte[] bytes = Encoding.ASCII.GetBytes("TPAK"); stream.Write(bytes, 0, bytes.Length); //第一次写入,文件头TPAK,4字节,{54,50,41,48} bytes = this.getIntegerBytes(1); stream.Write(bytes, 0, bytes.Length); bytes = this.getIntegerBytes(0); stream.Write(bytes, 0, bytes.Length); bytes = this.getIntegerBytes(0); stream.Write(bytes, 0, bytes.Length); //常量写入 整数 1 0 0,合计12字节,{1,0,0,0, 0,0,0,0, 0,0,0,0} byte[] buffer = Encoding.UTF8.GetBytes(info.Name); int num = (buffer.Length + 8) - (buffer.Length % 4); //num,下面三个部分的长度总和 bytes = this.getIntegerBytes(num); stream.Write(bytes, 0, bytes.Length); //下面三个部分的长度总和,4字节,例子 {14,00,00,00} 代表20 (14+8)-(14%4)=22-2=20=4+12+4 bytes = this.getIntegerBytes(buffer.Length); stream.Write(bytes, 0, bytes.Length); //buffer长度,4字节,例子 {0C,00,00,00} 代表12 stream.Write(buffer, 0, buffer.Length); //buffer内容写入(目录名)也就是主题的名字 bytes = new byte[4 - (buffer.Length % 4)]; stream.Write(bytes, 0, bytes.Length); //后padding,长度 4 - (buffer.Length % 4),全是{0},例如这里的长度是4 buffer = null; ArrayList vect = new ArrayList(); string[] fileSystemEntries = Directory.GetFileSystemEntries(filepath); //获取该目录下面的所有文件 for (int i = 0; i < fileSystemEntries.Length; i++) { this.listFile(fileSystemEntries[i], vect, "/"); //把这个文件夹里面所有的文件的名字加入数组,名字是相对路径的,开头一定是/,包含子目录里面的文件 } FileInfo info2 = new FileInfo(); //在vect的末尾加入一个全零的作为结束节点 info2.filelenth = 0; info2.filename = new byte[0]; info2.paddingsize = 0; vect.Add(info2); int[] numArray = new int[vect.Count << 1]; //总文件数左移一位int数组,左移相当于*2 2倍长度 bytes = this.getIntegerBytes(numArray.Length << 2); //左移2位相当于*4,4字节对齐? stream.Write(bytes, 0, bytes.Length); //写出上面数值,例如这里的{D0,00,00,00} 即是208 因此numArray长度52 vect.count长度26 num += 0x18 + (numArray.Length << 2); //num+24+numArray.Length << 2 也就是num+24+208=252 208为下面基址群的长度,24是前面8次write操作除去主题名buffer内容和buffer补丁这两次写入操作之外的六次写入操作的长度(6int=24) int count = vect.Count; for (int j = 0; j < count; j++) { numArray[j << 1] = num; //numArray偶数下标处,存放文件名基址 FileInfo info3 = (FileInfo) vect[j]; num += (info3.filename.Length + 4) + info3.paddingsize; //往后跳文件名长度+4字节+补丁 } for (int k = 0; k < count; k++) { numArray[(k << 1) + 1] = num; //numArray奇数下标处,存放文件内容基址 num += ((FileInfo) vect[k]).filelenth; //往后跳文件内容长度这么多 } for (int m = 0; m < numArray.Length; m++) { bytes = this.getIntegerBytes(numArray[m]); stream.Write(bytes, 0, bytes.Length); //遍历numArray,写出所有基址偏移量,例如这里的长度是52*4=208字节 } count--; //跳过末尾那个空的全零的结束节点 for (int n = 0; n < count; n++) { FileInfo info4 = (FileInfo) vect[n]; bytes = this.getIntegerBytes(info4.filename.Length); stream.Write(bytes, 0, bytes.Length); //写出文件名长度 // bytes = info4.filename; stream.Write(bytes, 0, bytes.Length); //写出文件名 bytes = new byte[info4.paddingsize]; stream.Write(bytes, 0, bytes.Length); //文件名的padding } bytes = new byte[4]; stream.Write(bytes, 0, 4); //{0,0,0,0}分割 byte[] buffer3 = new byte[0x4000]; //16384字节buffer 16kb int num8 = 0; for (int num9 = 0; num9 < count; num9++) { Console.WriteLine(filepath + Encoding.UTF8.GetString(((FileInfo) vect[num9]).filename));//调试输出文件名吧 FileStream stream2 = new FileStream(filepath + Encoding.UTF8.GetString(((FileInfo) vect[num9]).filename), FileMode.Open, FileAccess.Read);//读入要打包的文件 while ((num8 = stream2.Read(buffer3, 0, buffer3.Length)) > 0) { stream.Write(buffer3, 0, num8); //以16kb buffer读入要打包的文件,然后写出 } stream2.Close(); } stream.Close(); } } private void listFile(string filepath, ArrayList vect, string pathhead) { if (File.Exists(filepath)) //如果这是一个文件 { try { FileInfo info = new FileInfo(filepath); //内置的对象获取文件信息 FileInfo info2 = new FileInfo(); //覆盖的新的Fileinfo类型 info2.filename = Encoding.UTF8.GetBytes(pathhead + info.Name); //文件名头部信息+文件名,utf8哦 info2.paddingsize = 4 - (info2.filename.Length % 4); //4字节对齐补丁长度 info2.filelenth = (int) info.Length; //文件长度 vect.Add(info2); //加入到vect } catch (Exception) { } } else if (Directory.Exists(filepath)) //如果是一个子目录 { DirectoryInfo info3 = new DirectoryInfo(filepath); pathhead = pathhead + info3.Name + "/"; //文件名头部信息加上子目录名 string[] fileSystemEntries = Directory.GetFileSystemEntries(filepath); for (int i = 0; i < fileSystemEntries.Length; i++) { this.listFile(fileSystemEntries[i], vect, pathhead); //递归列文件,加入到vect } } }