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()
方法。他们实际达到的效果都是一样的