private void Decompress(object i) { try { blockData _block = _queueReader.Dequeue(); if (_block == null) { return; } using (MemoryStream ms = new MemoryStream(_block.CompressedBlock)) { using (GZipStream _gz = new GZipStream(ms, CompressionMode.Decompress)) { _gz.Read(_block.Block, 0, _block.Block.Length); byte[] decompressedData = new byte[_block.Block.Length]; _block.Block.CopyTo(decompressedData, 0); blockData block = new blockData(_block.ID, decompressedData); _queueWrite.EnqueueForWriting(block); } } } catch (Exception ex) { Console.WriteLine("Error in thread {0}. \n Error description: {1}", Thread.CurrentThread.Name, ex.Message); _cancelled = true; } }
private void Compress(object i) { try { blockData _block = _queueReader.Dequeue(); if (_block == null) { return; } using (MemoryStream _memoryStream = new MemoryStream()) { using (GZipStream cs = new GZipStream(_memoryStream, CompressionMode.Compress)) { cs.Write(_block.Block, 0, _block.Block.Length); } byte[] compressedData = _memoryStream.ToArray(); blockData _out = new blockData(_block.ID, compressedData); _queueWrite.EnqueueForWriting(_out); } } catch (Exception ex) { Console.WriteLine("Error in thread {0}. \n Error description: {1}", Thread.CurrentThread.Name, ex.Message); _cancelled = true; } }
//Здесь присваивается id новым блокам. Поскольку читается файл для сжатия одним потоком, то проблем с нарушением последовательности здесь не возникает. public void EnqueueForCompressing(byte[] block) { lock (locker) { if (isFin) { throw new InvalidOperationException("Queue already stopped"); } blockData _block = new blockData(blockId, block); queue.Enqueue(_block); blockId++; Monitor.PulseAll(locker); } }
public void EnqueueForWriting(blockData _block) { //А этот метод применяется, когда важна последовательность. Перед записью в выходной файл, в основном. int id = _block.ID; lock (locker) { if (isFin) { throw new InvalidOperationException("Adding new elements in stopped queue is impossible"); } while (id != blockId) { Monitor.Wait(locker); } queue.Enqueue(_block); blockId++; Monitor.PulseAll(locker); } }
private void Write() { try { using (FileStream _fileCompressed = new FileStream(outFile, FileMode.Append)) { blockData _block = _queueWrite.Dequeue(); if (_block == null) { return; } BitConverter.GetBytes(_block.Block.Length).CopyTo(_block.Block, 4); _fileCompressed.Write(_block.Block, 0, _block.Block.Length); } } catch (Exception ex) { Console.WriteLine("Error in thread {0}. \n Error description: {1}", Thread.CurrentThread.Name, ex.Message); _cancelled = true; } }
private void Read() { try { using (FileStream _compressedFile = new FileStream(inFile, FileMode.Open)) { while (_compressedFile.Position < _compressedFile.Length) { //Чтобы избежать нехватки памяти используется ограничение на максимальное количество блоков в очереди. По умолчанию оно представлено константой, значение которой можно изменить в коде класса GZ. //При необходимости можно применить и System.Environment.SystemPageSize или предоставить пользователю определять какое количество оперативной памяти он готов выделить программе //Но в ТЗ подобной задачи не ставилось, поэтому была использована константа. if (_queueReader.RetCount() <= maxBlock) { byte[] lengthOfBlock = new byte[8]; _compressedFile.Read(lengthOfBlock, 0, lengthOfBlock.Length); int blockLength = BitConverter.ToInt32(lengthOfBlock, 4); byte[] compressedData = new byte[blockLength]; lengthOfBlock.CopyTo(compressedData, 0); _compressedFile.Read(compressedData, 8, blockLength - 8); int _dataSize = BitConverter.ToInt32(compressedData, blockLength - 4); byte[] lastBlock = new byte[_dataSize]; blockData _block = new blockData(blockCounter, lastBlock, compressedData); _queueReader.EnqueueForWriting(_block); blockCounter++; } } _queueReader.Stop(); } } catch (Exception ex) { Console.WriteLine("Error in thread {0}. \n Error description: {1}", Thread.CurrentThread.Name, ex.Message); _cancelled = true; } }