/// <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);
            }
        }
예제 #2
0
        /// <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;
        }
예제 #3
0
        /// <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;
        }
예제 #10
0
        public DataStreamDefinition(int contentsBlockReference, int streamLengthInBytes)
        {
            MethodArgumentValidator.ThrowIfNegative(contentsBlockReference, "contentsBlockReference");
            MethodArgumentValidator.ThrowIfNegative(streamLengthInBytes, "streamLengthInBytes");

            _contentsBlockIndex  = contentsBlockReference;
            _streamLengthInBytes = streamLengthInBytes;
        }
예제 #11
0
        /// <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;
        }
예제 #12
0
        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;
        }
예제 #13
0
        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);
            }
        }
예제 #19
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);
            }
        }
예제 #20
0
        /// <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);
            }
        }