/// <summary> /// 同步解压一个IFS文件内存流 /// </summary> /// <param name="filePath"></param> /// <param name="outDir"></param> /// <returns></returns> public static bool SyncUnarchiveIFSFile(MemoryStream fileS, string outDir) { if (FileUtil.IsDirectoryExist(outDir)) { FileUtil.ClearDirectory(outDir); } else { FileUtil.CreateDirectory(outDir); } // JW.Common.Log.LogD("Begin->"); Stopwatch st = new Stopwatch(); st.Start(); // IFSFile ifsFile = new IFSFile(); //获取签名 byte[] bbs = new byte[16]; int offset = 0; fileS.Read(bbs, 0, 16); uint sig = (uint)ConvertBytesToInt(bbs, ref offset); if (sig != IFSFile.IFSSignature) { JW.Common.Log.LogE("IFSArchiver SyncUnarchiveIFSFile Error Signature "); fileS.Close(); return(false); } ifsFile.Signature = sig; //获取压缩方式 ifsFile.CompressType = (IFSCompressType)ConvertBytesToInt(bbs, ref offset); //条目个数 ifsFile.EntryCount = ConvertBytesToInt(bbs, ref offset); //名称长度 int entryNameL = ConvertBytesToInt(bbs, ref offset); if (ifsFile.EntryCount == 0) { JW.Common.Log.LogE("IFSArchiver SyncUnarchiveIFSFile Error EntryCount"); fileS.Close(); return(false); } //条目名称段 ifsFile.Entrys = new IFSEntry[ifsFile.EntryCount]; for (int i = 0; i < ifsFile.EntryCount; i++) { ifsFile.Entrys[i] = new IFSEntry(); } // bbs = null; // byte[] names = new byte[entryNameL]; fileS.Read(names, 0, entryNameL); offset = 0; //读取条目名称 for (int i = 0; i < ifsFile.EntryCount; i++) { IFSEntry entry = ifsFile.Entrys[i]; entry.Name = ConvertBytesToString(names, ref offset); } //条目数据位置 offset = 0; names = null; byte[] poss = new byte[ifsFile.EntryCount * 4]; fileS.Read(poss, 0, ifsFile.EntryCount * 4); for (int i = 0; i < ifsFile.EntryCount; i++) { IFSEntry entry = ifsFile.Entrys[i]; int vv = ConvertBytesToInt(poss, ref offset); entry.DataPos = vv; } offset = 0; poss = null; #region 无压缩 直接解压 //无压缩 直接解压 if (ifsFile.CompressType == IFSCompressType.None) { bool isOk = false; try { //公用buffer byte[] buffer = new byte[4 * 1024]; //解压数据到文件 for (int i = 0; i < ifsFile.EntryCount; i++) { IFSEntry entry = ifsFile.Entrys[i]; string outPath = FileUtil.CombinePaths(outDir, entry.Name); string directory = Path.GetDirectoryName(outPath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } FileStream output = new FileStream(outPath, FileMode.Create); try { fileS.Seek(entry.DataPos, SeekOrigin.Begin); byte[] ll = new byte[4]; fileS.Read(ll, 0, 4); offset = 0; int vv = ConvertBytesToInt(ll, ref offset); entry.DataSize = vv; // bool copying = true; int processed = 0; while (copying) { int bytesRead = fileS.Read(buffer, 0, buffer.Length); if (bytesRead > 0) { if (entry.DataSize <= bytesRead) { output.Write(buffer, 0, entry.DataSize); copying = false; } else { processed += bytesRead; if (processed > entry.DataSize) { output.Write(buffer, 0, bytesRead - (processed - entry.DataSize)); copying = false; } else { output.Write(buffer, 0, bytesRead); copying = true; } } } else { copying = false; } } // output.Flush(); } catch (Exception exc) { JW.Common.Log.LogE("Failed:" + entry.Name + "---" + exc.ToString()); } finally { output.Close(); output.Dispose(); output = null; } } } catch (Exception exc) { JW.Common.Log.LogE("IFSArchiver SyncUnarchiveIFSFile:" + exc.ToString()); isOk = false; } finally { st.Stop();//终止计时 JW.Common.Log.LogD("Done:" + st.ElapsedMilliseconds.ToString()); fileS.Close(); fileS.Dispose(); fileS = null; } st.Stop();//终止计时 JW.Common.Log.LogD("Done:" + st.ElapsedMilliseconds.ToString()); return(isOk); } #endregion // if (ifsFile.CompressType == IFSCompressType.LZMA) { bool isOk = DoUnarchiveLZMAIFSFile(ifsFile, outDir, fileS); st.Stop(); JW.Common.Log.LogD("Done:" + st.ElapsedMilliseconds.ToString()); return(isOk); } return(true); }
// private static bool DoUnarchiveLZMAIFSFile(IFSFile ifsFile, string outDir, Stream fileS) { bool isOk = true; try { //公用buffer byte[] buffer = new byte[4 * 1024]; int offset = 0; //解压数据到文件 for (int i = 0; i < ifsFile.EntryCount; i++) { IFSEntry entry = ifsFile.Entrys[i]; JW.Common.Log.LogD("Un LZMA File:" + entry.Name); // fileS.Seek(entry.DataPos, SeekOrigin.Begin); byte[] ll = new byte[4]; fileS.Read(ll, 0, 4); offset = 0; int vv = ConvertBytesToInt(ll, ref offset); entry.DataSize = vv; //解压 string outPath = FileUtil.CombinePaths(outDir, entry.Name); string directory = Path.GetDirectoryName(outPath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } FileStream output = new FileStream(outPath, FileMode.Create); try { SevenZip.Compression.LZMA.Decoder coder = new SevenZip.Compression.LZMA.Decoder(); byte[] properties = new byte[5]; fileS.Read(properties, 0, 5); byte[] fileLengthBytes = new byte[8]; fileS.Read(fileLengthBytes, 0, 8); long fileLength = BitConverter.ToInt64(fileLengthBytes, 0); coder.SetDecoderProperties(properties); coder.Code(fileS, output, entry.DataSize, fileLength, null); output.Flush(); } catch (Exception exc) { JW.Common.Log.LogE("LZMA Failed:" + entry.Name + "---" + exc.ToString()); } finally { output.Close(); output.Dispose(); output = null; } } } catch (Exception exc) { JW.Common.Log.LogE("LZMA Failed:" + exc.ToString()); isOk = false; } finally { fileS.Close(); fileS.Dispose(); } return(isOk); }
//归档一批文件 private static bool DoArchiveDir(string[] needfiles, string indir, string outPath, IFSCompressType compressType) { if (needfiles == null || needfiles.Length == 0) { return(false); } // int fileCnt = needfiles.Length; // IFSFile ifsFile = new IFSFile(); ifsFile.EntryCount = fileCnt; ifsFile.CompressType = compressType; ifsFile.Entrys = new IFSEntry[fileCnt]; for (int i = 0; i < fileCnt; i++) { ifsFile.Entrys[i] = new IFSEntry(); } // //初始化条目 for (int i = 0; i < fileCnt; i++) { IFSEntry entry = ifsFile.Entrys[i]; string relativePath = FileUtil.GetRelativePath(needfiles[i], indir); entry.Name = relativePath; entry.DataSize = FileUtil.GetFileLength(needfiles[i]); } int entryNameSegL = 0; //写入开始 int begin = 0; //签名 begin += 4; //压缩方式 begin += 4; //条目个数 begin += 4; //条目名字段长度 begin += 4; //条目名称信息 for (int i = 0; i < ifsFile.Entrys.Length; i++) { IFSEntry entry = ifsFile.Entrys[i]; int l = GetStringBytesLength(entry.Name); begin += l; entryNameSegL += l; } //条目数据位置段 for (int i = 0; i < ifsFile.Entrys.Length; i++) { begin += 4; } //设置 for (int i = 0; i < ifsFile.Entrys.Length; i++) { IFSEntry entry = ifsFile.Entrys[i]; if (i == 0) { entry.DataPos = begin; } else { IFSEntry entryPre = ifsFile.Entrys[i - 1]; //数据开始位置是上一个的开始位置+4+L entry.DataPos = entryPre.DataPos + 4 + entryPre.DataSize; } } //开始写 //写大文件 FileStream outIfs = new FileStream(outPath, FileMode.Create); //先写入文件头签名 byte[] bb = ConvertIntToBytes((int)ifsFile.Signature); outIfs.Write(bb, 0, bb.Length); //写入压缩方式 bb = ConvertIntToBytes((int)ifsFile.CompressType); outIfs.Write(bb, 0, bb.Length); //条目个数 bb = ConvertIntToBytes(ifsFile.Entrys.Length); outIfs.Write(bb, 0, bb.Length); //条目名称总长度 bb = ConvertIntToBytes(entryNameSegL); outIfs.Write(bb, 0, bb.Length); //条目名字信息 for (int i = 0; i < ifsFile.Entrys.Length; i++) { IFSEntry entry = ifsFile.Entrys[i]; byte[] bbs = ConvertStringToBytes(entry.Name); //名字 outIfs.Write(bbs, 0, bbs.Length); } //条目数据位置开始位置索引写入 for (int i = 0; i < ifsFile.Entrys.Length; i++) { IFSEntry entry = ifsFile.Entrys[i]; byte[] bbs = ConvertIntToBytes(entry.DataPos); //名字 outIfs.Write(bbs, 0, bbs.Length); } try { //写入所有文件数据 for (int i = 0; i < ifsFile.Entrys.Length; i++) { IFSEntry entry = ifsFile.Entrys[i]; //长度 byte[] ddl = ConvertIntToBytes(entry.DataSize); outIfs.Write(ddl, 0, ddl.Length); //写入数据 byte[] fileData = FileUtil.ReadFile(needfiles[i]); outIfs.Write(fileData, 0, entry.DataSize); } } catch (Exception exc) { JW.Common.Log.LogE("Archive Exception:" + exc.ToString()); return(false); } outIfs.Flush(); outIfs.Close(); return(true); }