private static void CompressWorkThread(object param) { CompressWork cw = (CompressWork)param; CompressEntry ce; while (cw.Input.TryTake(out ce)) { ce.DataRec = GetData(ce.ACE.GetData(), ce.ACE.Filename, cw.Compress); cw.Compressed.Add(ce); } }
public static void Create(System.IO.Stream output, IEnumerable<ArchiveCreateEntry> files, ArchiveFlags flags, CompressType compress, Action<double, string> onProgress) { if (!files.Any()) throw new IrosArcException("Can't create an archive that contains no files"); var sw = new System.Diagnostics.Stopwatch(); sw.Start(); double total = files.Count() + 2; int count = 0; onProgress(count / total, ""); ArcHeader h = new ArcHeader() { Flags = flags, Version = MAX_VERSION, Directory = 16 }; List<DirectoryEntry> entries = files.Select(f => new DirectoryEntry() { Filename = f.Filename, Flags = 0, }).ToList(); int dsize = entries.Select(e => (int)e.GetSize()).Sum(); h.Save(output); output.WriteInt(entries.Count); long position = h.Directory + dsize + 4; onProgress(++count / total, "Wrote header"); int index = 0; var combined = entries.Zip(files, (d,e) => new { Dir = d, ACE = e }).ToList(); var cw = new CompressWork() { Input = new System.Collections.Concurrent.ConcurrentBag<CompressEntry>(), Compressed = new System.Collections.Concurrent.BlockingCollection<CompressEntry>(8), Compress = compress }; foreach (var comb in combined) { cw.Input.Add(new CompressEntry() { ACE = comb.ACE, Dir = comb.Dir }); } foreach (int _ in Enumerable.Range(0, 8)) System.Threading.ThreadPool.QueueUserWorkItem(CompressWorkThread, cw); int filesDone = 0; while (filesDone < combined.Count) { var entry = cw.Compressed.Take(); entry.Dir.Offset = position; var data = entry.DataRec.Data; if (entry.DataRec.Compressed) entry.Dir.Flags |= FileFlags.CompressLZMA; entry.Dir.Length = data.Length; output.Position = position; output.Write(data, 0, data.Length); position += entry.Dir.Length; onProgress(++count / total, "Written " + entry.ACE.Filename); index++; filesDone++; } output.Position = h.Directory + 4; foreach (var entry in entries) { entry.Save(output); } sw.Stop(); onProgress(++count / total, String.Format("Complete: {0} files, {1:0.0}MB in {2} seconds", entries.Count, output.Length / (1024f*1024f), sw.Elapsed.TotalSeconds)); }