【问题标题】:FileStream: is buffer automatically flushed when full?FileStream:缓冲区满时是否自动刷新?
【发布时间】:2018-07-03 05:27:37
【问题描述】:

在 WCF 服务中,我有一个 FileStream,它应该会创建一个巨大的文件。

WCF 服务中的过程定期接收必须写入FileStream 的字节块。 FileStream 使用默认缓冲区大小。

我的程序接收块中的字节,其大小与 FileStream 缓冲区的大小相同,可能是最后一个块除外。该过程将完整的块写入 FileStream。因此,在大多数写入之后,FileStream 的缓冲区应该是满的。

问题:是否会自动刷新已满的缓冲区,还是应该在我认为缓冲区已满时刷新?

如果自动刷新完整的缓冲区,那么我的 Flush 弊大于利,因为它会在缓冲区已经刷新后立即 Flush。

代码如下:

async Task PersistData(byte[] receivedData)
{
    // write all bytes in one write to the FileStream:
    await stream.WriteAsync(receivedData, 0, receivedData.Length);

    // This will have filled the buffer to the brim.
    // Should I Flush or did the FileStream already Flush?
    await stream.FlushAsync();
}

【问题讨论】:

  • 你不需要冲洗它。
  • 考虑这个思想实验 - 你决定每次都进行刷新,但你在每次写入之前之前而不是之后进行。您会期望它具有大致相同的整体行为。这就是当你收到 next 块并且缓冲区碰巧仍然是满的时候将会发生的事情。所以我希望添加冲洗不会产生整体影响。

标签: c# filestream flush


【解决方案1】:

WriteAsync 方法总是根据实现为你调用flush

private FileStreamAsyncResult BeginWriteAsync(byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject)
        {
            Contract.Assert(_isAsync);

            if (!CanWrite) __Error.WriteNotSupported();

            Contract.Assert((_readPos == 0 && _readLen == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLen), "We're either reading or writing, but not both.");

            if (_isPipe)
            {
                // Pipes are ----ed up, at least when you have 2 different pipes
                // that you want to use simultaneously.  When redirecting stdout
                // & stderr with the Process class, it's easy to deadlock your
                // parent & child processes when doing writes 4K at a time.  The
                // OS appears to use a 4K buffer internally.  If you write to a
                // pipe that is full, you will block until someone read from 
                // that pipe.  If you try reading from an empty pipe and 
                // FileStream's BeginRead blocks waiting for data to fill it's 
                // internal buffer, you will be blocked.  In a case where a child
                // process writes to stdout & stderr while a parent process tries
                // reading from both, you can easily get into a deadlock here.
                // To avoid this deadlock, don't buffer when doing async IO on
                // pipes.   
                Contract.Assert(_readPos == 0 && _readLen == 0, "FileStream must not have buffered data here!  Pipes should be unidirectional.");

                if (_writePos > 0)
                    FlushWrite(false);

                return BeginWriteCore(array, offset, numBytes, userCallback, stateObject);
            }

            // Handle buffering.
            if (_writePos == 0)
            {
                if (_readPos < _readLen) FlushRead();
                _readPos = 0;
                _readLen = 0;
            }

            int n = _bufferSize - _writePos;
            if (numBytes <= n)
            {
                if (_writePos == 0) _buffer = new byte[_bufferSize];
                Buffer.InternalBlockCopy(array, offset, _buffer, _writePos, numBytes);
                _writePos += numBytes;

                // Return a synchronous FileStreamAsyncResult
                return FileStreamAsyncResult.CreateBufferedReadResult(numBytes, userCallback, stateObject, true);
            }

            if (_writePos > 0)
                FlushWrite(false);

            return BeginWriteCore(array, offset, numBytes, userCallback, stateObject);
        }
#endif // FEATURE_ASYNC_IO

【讨论】:

  • WriteAsync 调用 BeginWriteAsync,您展示了其中的代码。 n 是缓冲区中未使用的字节数。如果buffer还有足够的空间,就会将数据复制到buffer中,并且nt Flushed(返回if (numBytes
猜你喜欢
  • 2011-12-03
  • 2011-10-05
  • 1970-01-01
  • 2021-10-01
  • 1970-01-01
  • 2020-04-06
  • 2011-10-18
  • 2015-08-10
  • 2020-03-28
相关资源
最近更新 更多