/// <summary> /// /// </summary> /// <param name="newSize"></param> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="NoFreeBlocksException"></exception> /// <exception cref="ArgumentException"></exception> /// <exception cref="InconsistentDataDetectedException"></exception> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="MaximumFileSizeReachedException"></exception> public override void SetSize(int newSize) { MethodArgumentValidator.ThrowIfNegative(newSize, "newSize"); if (newSize == this.CurrentSize) { return; } if (newSize > this.MaximumSize) { throw new MaximumFileSizeReachedException( "Не удалось установить размер структуры в {0} байт. Максимальный размер - {1} байт.".FormatWith( newSize, this.MaximumSize)); } if (newSize > this.CurrentSize) { this.MakeLonger(newSize - this.CurrentSize); } else { this.MakeShorter(newSize); } }
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="InvalidOperationException"></exception> public void WriteBytes(byte[] array, int startingPosition, int length) { MethodArgumentValidator.ThrowIfNull(array, "array"); MethodArgumentValidator.ThrowIfNegative(startingPosition, "startingPosition"); MethodArgumentValidator.ThrowIfNegative(length, "length"); if ((startingPosition + length) > array.Length) { throw new ArgumentException("В массиве, начиная с позиции {0}, не найдется следующего числа байт для записи: {1}".FormatWith(startingPosition, length)); } if (this.IsAtEndOfBlock) { throw new InvalidOperationException("Запись за пределами границ блока не разрешена"); } int positionAfterWriting = this.Position + length; if (positionAfterWriting > this.SizeInBytes) { throw new ArgumentException("Запись невозможна: попытка записи за пределами массива"); } _disk.WriteBytesToBlock(BlockIndex, array, startingPosition, _position, length); if ((positionAfterWriting > this.OccupiedSpaceInBytes) && (this.OccupiedSpaceInBytes < this.SizeInBytes)) { this.OccupiedSpaceInBytes += (positionAfterWriting - this.OccupiedSpaceInBytes); } this.Position = positionAfterWriting; }
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> public DiskBlock(IVirtualDisk disk, int index, int occupiedSpaceInBytes, int position) { if (disk == null) { throw new ArgumentNullException("disk"); } MethodArgumentValidator.ThrowIfNegative(index, "index"); MethodArgumentValidator.ThrowIfNegative(occupiedSpaceInBytes, "occupiedSpaceInBytes"); MethodArgumentValidator.ThrowIfNegative(position, "position"); if (index >= disk.NumberOfBlocks) { throw new ArgumentOutOfRangeException("index"); } if (occupiedSpaceInBytes > disk.BlockSizeInBytes) { throw new ArgumentOutOfRangeException("occupiedSpaceInBytes"); } if (position > disk.BlockSizeInBytes) { throw new ArgumentOutOfRangeException("position"); } _disk = disk; _blockIndex = index; this.OccupiedSpaceInBytes = occupiedSpaceInBytes; this.SizeInBytes = _disk.BlockSizeInBytes; _position = position; }
/// <summary> /// Устанавливает указатель текущего положения в потоке в новое место. /// Примечание: за границу потока установить указатель нельзя (допускается лишь устанавливать ее за последним записанным/считанным байтом). /// </summary> /// <param name="newPosition">Новая позиция указателя текущего положения.</param> /// <exception cref="InvalidOperationException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="ObjectDisposedException"></exception> public override void SetPosition(int newPosition) { lock (_stateChangeCriticalSection) { this.ThrowIfDisposed(); MethodArgumentValidator.ThrowIfNegative(newPosition, "newPosition"); if (newPosition > this.Length) { throw new ArgumentOutOfRangeException("newPosition", "Невозможно установить позицию за пределами потока данных."); } if (newPosition == this.Length) { this.MoveToEnd(); return; } int blockIndex = newPosition / _blockSize; _diskBlockEnumerator.SetPosition(blockIndex); _diskBlockEnumerator.Current.Position = newPosition % _blockSize; } }
/// <summary> /// /// </summary> /// <param name="blockIndex"></param> /// <param name="dataStreamToAddReferenceIn"></param> /// <param name="nodeOwningTheStream"></param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="InsufficientSpaceException"></exception> /// <exception cref="MaximumFileSizeReachedException"></exception> public void AddBlockReference(int blockIndex, DataStreamDefinition dataStreamToAddReferenceIn, Node nodeOwningTheStream) { if (dataStreamToAddReferenceIn == null) { throw new ArgumentNullException("dataStreamToAddReferenceIn"); } if (nodeOwningTheStream == null) { throw new ArgumentNullException("nodeOwningTheStream"); } MethodArgumentValidator.ThrowIfNegative(blockIndex, "blockIndex"); var streamStructureBuilder = new DataStreamStructureBuilder(dataStreamToAddReferenceIn, _virtualDisk, _freeBlockManager, _fileSystemNodeStorage, nodeOwningTheStream, AddressingSystemParameters.Default); // Note: никаких настоящих блокировок не использует. var parentFolderFileReferencesStream = new DataStream(streamStructureBuilder, AddressingSystemParameters.Default.BlockSize, new NullFileSystemObjectLockingManager(), Guid.NewGuid()); var nodeUpdatingStream = new DataStreamNodeUpdating(parentFolderFileReferencesStream, nodeOwningTheStream, _fileSystemNodeStorage); using (nodeUpdatingStream) { var stream = new MemoryStream(); var writer = new BinaryWriter(stream); writer.Write(blockIndex); nodeUpdatingStream.MoveToEnd(); nodeUpdatingStream.Write(stream.ToArray(), 0, (int)stream.Length); } }
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="ArgumentException"></exception> internal DataStream( IDataStreamStructureBuilder streamStructureBuilder, int blockSize, IFileSystemLockReleaseManager lockingManager, Guid idOfLockBeingHeld) { try { if (streamStructureBuilder == null) { throw new ArgumentNullException("streamStructureBuilder"); } if (lockingManager == null) { throw new ArgumentNullException("lockingManager"); } MethodArgumentValidator.ThrowIfIsDefault(idOfLockBeingHeld, "idOfLockBeingHeld"); MethodArgumentValidator.ThrowIfNegative(blockSize, "blockSize"); _streamStructureBuilder = streamStructureBuilder; _blockSize = blockSize; _lockingManager = lockingManager; _idOfLockBeingHeld = idOfLockBeingHeld; _diskBlockEnumerator = streamStructureBuilder.CreateEnumerator(); } catch (Exception) { GC.SuppressFinalize(this); throw; } }
/// <summary> /// /// </summary> /// <param name="freeSpaceBitmap"></param> /// <param name="blockIndexOffset"></param> /// <param name="freeSpaceMapLength"></param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="ArgumentException"></exception> public FreeBlockManagerBitArrayBased(BitArray freeSpaceBitmap, int blockIndexOffset, int freeSpaceMapLength) { MethodArgumentValidator.ThrowIfNull(freeSpaceBitmap, "freeSpaceBitmap"); MethodArgumentValidator.ThrowIfNegative(blockIndexOffset, "blockIndexOffset"); if (freeSpaceBitmap.Length != freeSpaceMapLength) { throw new ArgumentException("В Bitmap для разметки свободного места должно быть следующее число бит: {0}".FormatWith(freeSpaceMapLength)); } _freeSpaceBitmap = freeSpaceBitmap; _blockIndexOffset = blockIndexOffset; _freeSpaceMapLength = freeSpaceMapLength; int freeBlocksCount = 0; for (int i = 0; i < freeSpaceBitmap.Length; i++) { if (!freeSpaceBitmap[i]) { freeBlocksCount++; } } _freeBlockCount = freeBlocksCount; }
/// <summary> /// Устанавливает длину потока (беря себе или освобождая соответствующий объем дискового пространства). /// </summary> /// <param name="newLength">Новая длина потока</param> /// <exception cref="InsufficientSpaceException"></exception> /// <exception cref="ObjectDisposedException"></exception> public override void SetLength(int newLength) { lock (_stateChangeCriticalSection) { this.ThrowIfDisposed(); MethodArgumentValidator.ThrowIfNegative(newLength, "newLength"); if (newLength < _streamStructureBuilder.CurrentSize) { this.Shrink(newLength); return; } if (newLength == this.Length) { return; } int position = this.Position; this.MoveToEnd(); int numberOfZeroesToAdd = this.Length == 0 ? newLength : newLength - (_streamStructureBuilder.CurrentSize - 1); WriteZeroes(numberOfZeroesToAdd); this.SetPosition(position); } }
public AddressingSystemBlockSizes(int doubleIndirectBlockSize, int lastSingleIndirectBlockSize) { MethodArgumentValidator.ThrowIfNegative(doubleIndirectBlockSize, "doubleIndirectBlockSize"); MethodArgumentValidator.ThrowIfNegative(lastSingleIndirectBlockSize, "lastSingleIndirectBlockSize"); DoubleIndirectBlockSize = doubleIndirectBlockSize; LastSingleIndirectBlockSize = lastSingleIndirectBlockSize; }
public DataStreamDefinition(int contentsBlockReference, int streamLengthInBytes) { MethodArgumentValidator.ThrowIfNegative(contentsBlockReference, "contentsBlockReference"); MethodArgumentValidator.ThrowIfNegative(streamLengthInBytes, "streamLengthInBytes"); _contentsBlockIndex = contentsBlockReference; _streamLengthInBytes = streamLengthInBytes; }
/// <summary> /// Устанавливает в качестве текущего блок заданного номера. /// </summary> /// <param name="newPosition"></param> /// <exception cref="ArgumentOutOfRangeException"></exception> public void SetPosition(int newPosition) { if (newPosition == EnumeratorAddressable <IDiskBlock> .IndexOfPositionBeforeFirstElement) { this.Reset(); return; } MethodArgumentValidator.ThrowIfNegative(newPosition, "newPosition"); if (newPosition >= _numberOfBlocks) { throw new ArgumentOutOfRangeException("newPosition", "Невозможно установить позицию за границей массива"); } #region совсем топорная версия // if (newPosition < _position) // { // this.Reset(); // } // // while (_position != newPosition) // { // this.MoveNext(); // } // //return; #endregion var compositeIndex = new CompositeIndex(newPosition, new[] { _addressingSystemParameters.IndirectBlockReferencesCountInDoubleIndirectBlock, _addressingSystemParameters.DataBlockReferencesCountInSingleIndirectBlock }); var sizes = _blockSizesCalculator.GetSizesOfAddressingBlocksSufficientToStoreItems(newPosition); _doubleIndirectListEnumerator.SetPosition(compositeIndex.CompositeValue[0]); bool isLastDoubleIndirectionBlock = _doubleIndirectListEnumerator.IsAtLastElement; int numberOfSingleIndirectBlockReferences = isLastDoubleIndirectionBlock ? _addressingSystemSizesOfLastBlocks.LastSingleIndirectBlockSize : _addressingSystemParameters.DataBlockReferencesCountInSingleIndirectBlock; this.InitializeSingleIndirectionBlock( _doubleIndirectListEnumerator.Current, numberOfSingleIndirectBlockReferences, compositeIndex.CompositeValue[1]); this.InitializeCurrentBlockBrowser(); _position = newPosition; }
public FolderNode(string name, Guid id, int diskBlockIndex, int parentFolderBlockReference, DataStreamDefinition fileReferencesStreamDefinition, DataStreamDefinition folderReferencesStreamDefinition, DateTime creationTime, Guid version) : base(name, id, diskBlockIndex, version, creationTime) { MethodArgumentValidator.ThrowIfNull(fileReferencesStreamDefinition, "fileReferencesStream"); MethodArgumentValidator.ThrowIfNull(folderReferencesStreamDefinition, "folderReferencesStream"); MethodArgumentValidator.ThrowIfNegative(parentFolderBlockReference, "parentFolderBlockReference"); MethodArgumentValidator.ThrowIfNegative(diskBlockIndex, "diskBlockIndex"); MethodArgumentValidator.ThrowIfIsDefault(id, "id"); _fileReferencesStreamDefinition = fileReferencesStreamDefinition; _folderReferencesStreamDefinition = folderReferencesStreamDefinition; _parentFolderBlockReference = parentFolderBlockReference; }
internal VirtualFileSystemInfo(Version version, int blockSizeInBytes, int firstNonReservedDiskBlockIndex, int freeSpaceBitmapStartingBlock) { if (version == null) { throw new ArgumentNullException("version"); } MethodArgumentValidator.ThrowIfNegative(blockSizeInBytes, "blockSizeInBytes"); MethodArgumentValidator.ThrowIfNegative(firstNonReservedDiskBlockIndex, "firstNonReservedDiskBlockIndex"); MethodArgumentValidator.ThrowIfNegative(freeSpaceBitmapStartingBlock, "freeSpaceBitmapStartingBlock"); Version = version; BlockSizeInBytes = blockSizeInBytes; FirstNonReservedDiskBlockIndex = firstNonReservedDiskBlockIndex; FreeSpaceBitmapStartingBlock = freeSpaceBitmapStartingBlock; }
public NodeResolver( IVirtualDisk virtualDisk, FileSystemNodeStorage fileSystemNodeStorage, IEqualityComparer <string> namesComparer, int rootBlockIndex, string rootFolderPath, char directorySeparatorChar, IPathValidator pathValidator, PathBuilder pathBuilder) { if (virtualDisk == null) { throw new ArgumentNullException("virtualDisk"); } if (fileSystemNodeStorage == null) { throw new ArgumentNullException("fileSystemNodeStorage"); } if (namesComparer == null) { throw new ArgumentNullException("namesComparer"); } if (pathBuilder == null) { throw new ArgumentNullException("pathBuilder"); } if (String.IsNullOrEmpty(rootFolderPath)) { throw new ArgumentNullException("rootFolderPath"); } MethodArgumentValidator.ThrowIfNegative(rootBlockIndex, "rootBlockIndex"); if (rootBlockIndex >= virtualDisk.NumberOfBlocks) { throw new ArgumentOutOfRangeException("rootBlockIndex"); } _virtualDisk = virtualDisk; _pathBuilder = pathBuilder; _fileSystemNodeStorage = fileSystemNodeStorage; _namesComparer = namesComparer; _rootBlockIndex = rootBlockIndex; _rootFolderPath = rootFolderPath; _directorySeparatorChar = directorySeparatorChar; _pathValidator = pathValidator; }
/// <summary> /// /// </summary> /// <param name="blockIndex"></param> /// <exception cref="ArgumentOutOfRangeException"></exception> public void MarkBlockAsFree(int blockIndex) { MethodArgumentValidator.ThrowIfNegative(blockIndex, "blockIndex"); int blockIndexWithOffset = blockIndex - _blockIndexOffset; if ((blockIndexWithOffset > _freeSpaceBitmap.Length) || (blockIndexWithOffset < 0)) { throw new ArgumentOutOfRangeException("blockIndex"); } if (!_freeSpaceBitmap[blockIndexWithOffset]) { throw new BlockNotOccupiedException("Не удалось пометить блок с индексом {0} как свободный. Он не занят.".FormatWith(blockIndex)); } _freeSpaceBitmap[blockIndexWithOffset] = false; _freeBlockCount++; }
/// <summary> /// /// </summary> /// <param name="blockIndex"></param> /// <param name="bytesToWrite"></param> /// <param name="arrayOffset"></param> /// <param name="blockOffset"></param> /// <param name="numberOfBytesToWrite"></param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="ObjectDisposedException"></exception> public void WriteBytesToBlock(int blockIndex, byte[] bytesToWrite, int arrayOffset, int blockOffset, int numberOfBytesToWrite) { lock (_diskAccessCriticalSection) { ThrowIfDisposed(); MethodArgumentValidator.ThrowIfNull(bytesToWrite, "bytesToWrite"); MethodArgumentValidator.ThrowIfNegative(blockOffset, "blockOffset"); MethodArgumentValidator.ThrowIfNegative(numberOfBytesToWrite, "numberOfBytesToWrite"); MethodArgumentValidator.ThrowIfNegative(arrayOffset, "arrayOffset"); this.MakeSureBlockIndexArgumentIsSane(blockIndex, "blockIndex"); if (blockOffset >= this.BlockSizeInBytes) { throw new ArgumentOutOfRangeException("blockOffset"); } if (arrayOffset > bytesToWrite.Length) { throw new ArgumentOutOfRangeException("arrayOffset"); } if (numberOfBytesToWrite > this.BlockSizeInBytes) { throw new ArgumentOutOfRangeException("numberOfBytesToWrite"); } if ((blockOffset + numberOfBytesToWrite) > this.BlockSizeInBytes) { throw new ArgumentOutOfRangeException("blockOffset, numberOfBytesToWrite"); } if (bytesToWrite.Length < numberOfBytesToWrite) { throw new ArgumentOutOfRangeException("numberOfBytesToWrite", "Массиве данных слишком мал, чтобы из него можно было считать следующее число байт: {0}.".FormatWith(numberOfBytesToWrite)); } this.SeekToBlockStartWithInBlockOffset(blockIndex, blockOffset); _backingStream.Write(bytesToWrite, arrayOffset, numberOfBytesToWrite); } }
/// <summary> /// /// </summary> /// <param name="indexOfBlockToWriteTo"></param> /// <param name="bytesToWrite"></param> /// <param name="startingPosition"></param> /// <param name="numberOfBytesToWrite"></param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="ArgumentException"></exception> private void WriteBytesToBlock(int indexOfBlockToWriteTo, byte[] bytesToWrite, int startingPosition, int numberOfBytesToWrite) { MethodArgumentValidator.ThrowIfNull(bytesToWrite, "bytesToWrite"); MethodArgumentValidator.ThrowIfNegative(indexOfBlockToWriteTo, "indexOfBlockToWriteTo"); MethodArgumentValidator.ThrowIfNegative(startingPosition, "startingPosition"); MethodArgumentValidator.ThrowIfNegative(numberOfBytesToWrite, "numberOfBytesToWrite"); if ((startingPosition + numberOfBytesToWrite) > bytesToWrite.Length) { throw new ArgumentException("Не получится записать {0} байтов, начиная с позиции {1}. В массиве всего следующее число байт: {2}.".FormatWith(numberOfBytesToWrite, startingPosition, bytesToWrite.Length)); } if (bytesToWrite.Length > BlockSizeInBytes) { throw new ArgumentException("Невозможно записать данные в блок: в блок можно записать, максимум, {0} байт.".FormatWith(BlockSizeInBytes), "bytesToWrite"); } this.MakeSureBlockIndexArgumentIsSane(indexOfBlockToWriteTo, "indexOfBlockToWriteTo"); this.SeekToBlockStart(indexOfBlockToWriteTo); _backingStream.Write(bytesToWrite, startingPosition, numberOfBytesToWrite); }
/// <summary> /// /// </summary> /// <param name="indexOfBlockToReadFrom"></param> /// <param name="startingPosition"></param> /// <param name="numberOfBytesToRead"></param> /// <returns></returns> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="ArgumentException"></exception> /// <exception cref="ObjectDisposedException"></exception> public byte[] ReadBytesFromBlock(int indexOfBlockToReadFrom, int startingPosition, int numberOfBytesToRead) { lock (_diskAccessCriticalSection) { ThrowIfDisposed(); MethodArgumentValidator.ThrowIfNegative(indexOfBlockToReadFrom, "indexOfBlockToReadFrom"); MethodArgumentValidator.ThrowIfNegative(numberOfBytesToRead, "numberOfBytesToRead"); if ((startingPosition + numberOfBytesToRead) > BlockSizeInBytes) { throw new ArgumentException("Не удалось прочитать данные: попытка чтения за границами блока.", "startingPosition, numberOfBytesToRead"); } this.MakeSureBlockIndexArgumentIsSane(indexOfBlockToReadFrom, "indexOfBlockToReadFrom"); SeekToBlockStartWithInBlockOffset(indexOfBlockToReadFrom, startingPosition); var bytesRead = new byte[numberOfBytesToRead]; _backingStream.Read(bytesRead, 0, numberOfBytesToRead); return(bytesRead); } }
/// <summary> /// Записывает в поток указанное число байт из массива. Если поток недостаточного размера, он увеличивается. /// Запись производится, начиная с текущей позиции в потоке. /// </summary> /// <param name="bytesToWrite">Массив байт, данные из которого следует записать в поток.</param> /// <param name="arrayOffset">Указывает начальную позицию в массиве (<paramref name="bytesToWrite"/>), с которой нужно брать байты для записи.</param> /// <param name="count">Количество байт, которые, начиная с <paramref name="arrayOffset"/>, следует записать в поток.</param> /// <exception cref="InsufficientSpaceException"></exception> /// <exception cref="ObjectDisposedException"></exception> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentException"></exception> /// <exception cref="MaximumFileSizeReachedException"></exception> public override void Write(byte[] bytesToWrite, int arrayOffset, int count) { if (bytesToWrite == null) { throw new ArgumentNullException("bytesToWrite"); } // Note: этому методу, подозреваю, сильно не хватило тестов. MethodArgumentValidator.ThrowIfNegative(arrayOffset, "arrayOffset"); MethodArgumentValidator.ThrowIfNegative(count, "count"); if ((arrayOffset + count) > bytesToWrite.Length) { throw new ArgumentException("Не удастся прочитать {0} байт, начиная с позиции {1} в массиве. В массиве содержится следующее число элементов: {2}".FormatWith(count, arrayOffset, bytesToWrite.Length)); } if (count == 0) { return; } Monitor.Enter(_stateChangeCriticalSection); try { this.ThrowIfDisposed(); int numberOfBytesAvailable = this.Length - this.Position; // есть еще зажатые в выделенном блоке, ими мы занимаемся ниже. int numberOfBytesNeeded = count - numberOfBytesAvailable; bool canAvoidNewBlocksAcquisition = _diskBlockEnumerator.Current.NumberOfBytesCanBeWrittenAtCurrentPosition >= numberOfBytesNeeded; if ((numberOfBytesNeeded > 0) && !canAvoidNewBlocksAcquisition) { int oldBlockIndex = _diskBlockEnumerator.Position; int oldInsideBlockPosition = _diskBlockEnumerator.Current.Position; _streamStructureBuilder.SetSize(_streamStructureBuilder.CurrentSize + numberOfBytesNeeded); _diskBlockEnumerator = _streamStructureBuilder.CreateEnumerator(); _diskBlockEnumerator.SetPosition(oldBlockIndex); if (!_diskBlockEnumerator.Current.IsNull) { _diskBlockEnumerator.Current.Position = oldInsideBlockPosition; } } WriteBytesKnowingStreamLengthIsRight(bytesToWrite, arrayOffset, count); } catch (MaximumFileSizeReachedException) { throw new MaximumFileSizeReachedException("Не удаcтся записать {0} байт в файл: максимальный размер файла в текущей версии системы - {1} байт, текущий размер файла - {2} байт.".FormatWith(count, _streamStructureBuilder.MaximumSize, this.Length)); } catch (NoFreeBlocksException) { throw new InsufficientSpaceException("Операция записи отменена: недостаточно места на диске для записи в поток следующего числа байт -- {0}".FormatWith(count)); } finally { Monitor.Exit(_stateChangeCriticalSection); } }
/// <summary> /// Читает байты из потока в заданный массив, начиная с текущей позиции в потоке. /// </summary> /// <param name="bufferToReadBytesInto">Байтовый массив, в который следует читать данные.</param> /// <param name="offset">Стартовая позиция в массиве <paramref name="bufferToReadBytesInto"/>, куда надо записывать данные из потока.</param> /// <param name="count">Число байт, которые следует считать из потока.</param> /// <returns>Число байт, которые удалось прочитать (за пределами потока читать нельзя, потому это число может оказаться меньше чем <paramref name="count"/>).</returns> /// <exception cref="ObjectDisposedException"></exception> /// <exception cref="InvalidOperationException"></exception> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="ArgumentNullException"></exception> public override int Read(byte[] bufferToReadBytesInto, int offset, int count) { lock (_stateChangeCriticalSection) { this.ThrowIfDisposed(); MethodArgumentValidator.ThrowIfNegative(offset, "offset"); MethodArgumentValidator.ThrowIfNegative(count, "count"); if (bufferToReadBytesInto == null) { throw new ArgumentNullException("bufferToReadBytesInto"); } if ((offset + count) > bufferToReadBytesInto.Length) { throw new ArgumentException("Не удастся прочитать {0} байт, начиная с позиции {1} в массиве. В массиве содержится следующее число элементов: {2}".FormatWith(count, offset, bufferToReadBytesInto.Length)); } int numberOfBytesReadable = this.Length - this.Position; if (count > numberOfBytesReadable) { count = numberOfBytesReadable; } int positionInArray = offset; int positionInArrayAfterAllHasBeenRead = offset + count; int numberOfBytesRead = 0; while (positionInArray != positionInArrayAfterAllHasBeenRead) { if (_diskBlockEnumerator.Current.IsAtEndOfReadableData) { if (!_diskBlockEnumerator.MoveNext()) { throw new InvalidOperationException("Не удалось прочитать заданное количество байт: попытка чтения за границами потока"); } } int numberOfBytesToRead = Math.Min( _diskBlockEnumerator.Current.OccupiedSpaceInBytes - _diskBlockEnumerator.Current.Position, positionInArrayAfterAllHasBeenRead - positionInArray); if (numberOfBytesToRead == 0) { throw new InvalidOperationException(); } int position = _diskBlockEnumerator.Current.Position; byte[] bytesRead = _diskBlockEnumerator.Current.ReadAll(); Array.Copy(bytesRead, position, bufferToReadBytesInto, positionInArray, numberOfBytesToRead); //zero instead of position positionInArray += numberOfBytesToRead; numberOfBytesRead += numberOfBytesToRead; _diskBlockEnumerator.Current.Position += numberOfBytesToRead; } return(numberOfBytesRead); } }