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
}
}
}