C# Position 和 Seek 方法的区别

前言

Position 和 Seek 方法功能重复,那我们改如何正确的使用它呢?为满足那奇怪好奇心,上微软官网搜了下源码,就把它记在这里,以备不时之需。

上源码

注 .NET Core 源码官网:.NET Core .NET FrameWork 源码官网:.NET FrameWork

public class MemoryStream : Stream
{
    private byte[] _buffer;
    private readonly int _origin;
    private int _position;
    private int _length;
    //...
    public override long Position
    {
        get
        {
            EnsureNotClosed();
            return _position - _origin;
        }
        set
        {
            if (value < 0)
                throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_NeedNonNegNum);

            EnsureNotClosed();

            if (value > MemStreamMaxLength)
                throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_StreamLength);
            _position = _origin + (int)value;
        }
    }

    public override long Seek(long offset, SeekOrigin loc)
    {
        EnsureNotClosed();

        if (offset > MemStreamMaxLength)
            throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_StreamLength);

        switch (loc)
        {
            case SeekOrigin.Begin:
                {
                    int tempPosition = unchecked(_origin + (int)offset);
                    if (offset < 0 || tempPosition < _origin)
                        throw new IOException(SR.IO_SeekBeforeBegin);
                    _position = tempPosition;
                    break;
                }
            case SeekOrigin.Current:
                {
                    int tempPosition = unchecked(_position + (int)offset);
                    if (unchecked(_position + offset) < _origin || tempPosition < _origin)
                        throw new IOException(SR.IO_SeekBeforeBegin);
                    _position = tempPosition;
                    break;
                }
            case SeekOrigin.End:
                {
                    int tempPosition = unchecked(_length + (int)offset);
                    if (unchecked(_length + offset) < _origin || tempPosition < _origin)
                        throw new IOException(SR.IO_SeekBeforeBegin);
                    _position = tempPosition;
                    break;
                }
            default:
                throw new ArgumentException(SR.Argument_InvalidSeekOrigin);
        }

        Debug.Assert(_position >= 0, "_position >= 0");
        return _position;
    }
}

我们可以看到 Position 能获取或设置相对于 _origin 的位置 (_origin 在实例化流时,通过 index 参数指定)。 Seek方法则是设置相对于 _origin的位置,而获取整个流的当前位置,获取时和Position不同。
另外,Seek 方法可以在不知道流的长度的情况下,获取后面的部分。例如:获取后 5 位 => stream.Seek(-5,SeekOrigin.End)

总结

简单的重置流的读取用 stream.Position = 0,需要实现更加复杂的功能可以使用 stream.Seek()方法。他们实际达到的效果都是一样的

posted @ 2020-09-22 10:23  一颗花生豆  阅读(1990)  评论(0编辑  收藏  举报