コード例 #1
0
        /// <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;
            }
        }
コード例 #2
0
        /// <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);
            }
        }