private void Compress(Stream source, Stream dest) { //Вычислим кол-во блоков var blocksCount = (int)(source.Length / BlockSize + (source.Length % BlockSize > 0 ? 1 : 0)); //Создадим заголовок var header = new DummyCompressedDataHeader(blocksCount); //И оставим в потоке назначения место под запись заголовка dest.Seek(header.SelfSize, SeekOrigin.Begin); source.Seek(0, SeekOrigin.Begin); var blockIndex = 0; var destBlockIndex = 0; var doneEvent = new AutoResetEvent(false); while (source.Position < source.Length) //Пока не прочли весь исходный файл { if (_cancellationToken.WaitOne(0)) { return; //Если было событие отмены - вывалимся } var data = new byte[BlockSize]; //Читаем блок var dataLength = source.Read(data, 0, BlockSize); var index = blockIndex; //Отправляем в очередь на упаковку AddToDeCompressionQueue(CompressionMode.Compress, data, dataLength, result => { lock (_destLocker) { //После упаковки блока отметим в заголовке его расположение и реальный и исходный размеры header.Blocks[destBlockIndex].Number = index; header.Blocks[destBlockIndex].Size = result.Length; header.Blocks[destBlockIndex].SourceSize = dataLength; //Ну и запишем его dest.Write(result, 0, result.Length); //Если записали все, сигнализируем об этом if (++destBlockIndex == blocksCount) { doneEvent.Set(); } } }); blockIndex++; ReportProgress(blockIndex, blocksCount); } doneEvent.WaitOne(); //Подождем пока все потоки доработают lock (_destLocker) { //Когда все закончено, встанем в начала файла назначения dest.Seek(0, SeekOrigin.Begin); //И запишем заголовок header.WriteTo(dest); } }
private void Decompress(Stream source, Stream dest) { var header = DummyCompressedDataHeader.ReadFrom(source); //Прочтем хидер dest.Seek(0, SeekOrigin.Begin); var blockIndex = 0; var writedBlockCount = 0; var doneEvent = new AutoResetEvent(false); while (source.Position < source.Length) //Начнем читать исходный файл { if (_cancellationToken.WaitOne(0)) { return; //Если запросили прерывание - отвалимся } var sourceBlockSize = header.Blocks[blockIndex].Size; var sourceBlockIndex = header.Blocks[blockIndex].Number; var data = new byte[sourceBlockSize]; var dataLength = source.Read(data, 0, sourceBlockSize); if (dataLength != sourceBlockSize) { throw new FileLoadException("Исходный файл имеет неверный формат"); } AddToDeCompressionQueue(CompressionMode.Decompress, data, sourceBlockSize, result => { //Рассчитаем оригинальное смещение блока var blockOffset = header.CalcSourceBlockOffset(sourceBlockIndex); lock (_destLocker) { //И запишем его по оригинальному смещению dest.Seek(blockOffset, SeekOrigin.Begin); dest.Write(result, 0, result.Length); if (++writedBlockCount == header.BlocksCount) { doneEvent.Set(); } } }); blockIndex++; ReportProgress(blockIndex, header.BlocksCount); } doneEvent.WaitOne(); }
/// <summary> /// Читает заголовок из указанного потока /// </summary> /// <param name="source">Поток-источник</param> /// <returns></returns> internal static DummyCompressedDataHeader ReadFrom(Stream source) { var breader = new BinaryReader(source); var header = breader.ReadUInt32(); if (header != Header) { throw new FileLoadException("Указанный файл имеет неверный формат (Заголовок не соответствует ожидаемому)"); } var count = breader.ReadInt32(); var result = new DummyCompressedDataHeader(count); for (var idx = 0; idx < count; idx++) { result.Blocks[idx].ReadFrom(breader); } return(result); }