Exemplo n.º 1
0
        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);
            }
        }