/// <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; } }
private void Shrink(int newLength) { _streamStructureBuilder.SetSize(newLength); _diskBlockEnumerator = _streamStructureBuilder.CreateEnumerator(); this.MoveToEnd(); }
/// <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); } }