构造函数
如果创建一个FileStream,常见的参数例如路径Path、操作方式FileMode、权限FileAccess。
这里说下FileShare和SafeFileHandle。
我们知道在读取文件时,通常会有两个诉求:一是如何更快的读取文件内容;二是如何减少读取文件的消耗。常见的加快读取文件的方式是多线程读取,每个线程读取文件的一部分,这就涉及到文件的共享,有以下几种模式:
SafeFileHandle用的很少,一般来多语言交互的时候用到,比如在C++打开了一个文件,要把引用传递给C#,C#这边来读取文件,或者C#打开文件,传递给C++读取文件。这种情况出现的很少,如果真的需要C++和C#传递文件数据,一般会将文件路径传递,打开读取文件在一端进行,或者在一端打开读取文件后将包含数据的buffer传递到另一端。如果要用的话,示例如下:
- [DllImport("kernel32.dll", SetLastError = true, CharSet=CharSet.Unicode)]
- static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
- uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
- uint dwFlagsAndAttributes, IntPtr hTemplateFile);
-
- public void ReadFile()
- {
- SafeFileHandle fileHandle = CreateFile(
- "example.txt",
- GENERIC_READ,
- FILE_SHARE_READ,
- IntPtr.Zero,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- IntPtr.Zero
- );
-
- byte[] buffer = new byte[1024];
- using (FileStream fileStream = new FileStream(fileHandle, FileAccess.Read))
- {
- int bytesRead = fileStream.Read(buffer, 0, buffer.Length);
- //FileStream.SafeFileHandle.DangerousGetHandle() 获取文件句柄
- }
- }
方法
Read、Write、Dispose和Close没什么好说的,很常用。这里看看不常用的其他方法。
Read(Span
ReadExactly:其与Read的区别是,在读取一定的字节序列后,会推进流的位置,也即改变Position属性的值。
源码(反编译来的)
对于上层调用者来说,FileStream提供了一个中间缓存层。每多一个中间层,就需要在中间层中处理好中间层和下层的共同属性之间的关系,这里指Position的关系。
读取数据
- public override int Read([In][Out] byte[] array, int offset, int count)
- {
- if (array == null)
- {
- throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer"));
- }
-
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- }
-
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- }
-
- if (array.Length - offset < count)
- {
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
- }
-
- if (_handle.IsClosed)//这是SafeFileHandle
- {
- __Error.FileNotOpen();
- }
-
- bool flag = false;
- int num = _readLen - _readPos;//read和write共用一个buffer,readlen表示用于读数据的长度,这里求的是读数据buffer的剩余可用大小
- if (num == 0)//用于读的buffer的长度和位置相等,表示用于读的buffer用满了
- {
- if (!CanRead)
- {
- __Error.ReadNotSupported();
- }
-
- if (_writePos > 0)//此时需要清空写入的buffer
- {
- FlushWrite(calledFromFinalizer: false);
- }
-
- if (!CanSeek || count >= _bufferSize)//如果要求的count大于buffer的大小时,会直接将读出来的数据放入到指定的array中,少了copy的步骤
- { //如果FilsStream只是用于读数据,可以指定小的buffersize,将读到的数据直接放入指定的array中,减少从buffer到array的拷贝
- num = ReadCore(array, offset, count);
- _readPos = 0;
- _readLen = 0;
- return num;
- }
-
- if (_buffer == null)//实例化buffer
- {
- _buffer = new byte[_bufferSize];
- }
-
- num = ReadCore(_buffer, 0, _bufferSize);//注意,如果指定的count小于buffer,那么实际是按照buffersize的大小来读取数据的
- if (num == 0) //这样做是为了减少IO消耗,底层在读取磁盘数据时,会一次性读取扇区里的全部内容,而不是按照上层指定的读取只读取几个字节
- //因此,读文件的操作不一定真的有IO消耗,如果每次读的小,会用到这里的缓存数据
- {
- return 0;
- }
-
- flag = (num < _bufferSize);//这种情况表示文件大小(或者文件剩余大小)小于指定的buffer大小,buffer大小默认4kb
- _readPos = 0;
- _readLen = num;
- }
-
- if (num > count)
- {
- num = count;
- }
-
- Buffer.InternalBlockCopy(_buffer, _readPos, array, offset, num);//将buffer里的数据copy到指定的array中
- _readPos += num;//读数据时流的位置会增加
- if (!_isPipe && num < count && !flag)//isPipe一般为false,这种情况表示指定的count比读数据buffer的可用数据大
- { //步骤是先将buffer里的数据copy到指定的array中,然后再从文件中读剩余(count-num)个数据
- int num2 = ReadCore(array, offset + num, count - num);
- num += num2;
- _readPos = 0;//读数据的Buffer被读取完了,流的位置和大小都回置为0
- _readLen = 0;
- }
-
- return num;
- }
写入数据
- public override void Write(byte[] array, int offset, int count)
- {
- if (array == null)
- {
- throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer"));
- }
-
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- }
-
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- }
-
- if (array.Length - offset < count)
- {
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
- }
-
- if (_handle.IsClosed)
- {
- __Error.FileNotOpen();
- }
-
- if (_writePos == 0
- {
- if (!CanWrite)
- {
- __Error.WriteNotSupported();
- }
-
- if (_readPos < _readLen)//这种情况表示要写数据时,buffer中还有一些数据没被上层读完,需要情况,回退读的位置
- { //读写共用一个buffer,读时清空写的数据,写时清空读的数据
- FlushRead();
- }
-
- _readPos = 0;
- _readLen = 0;
- }
-
- if (_writePos > 0)
- {
- int num = _bufferSize - _writePos;//计算剩余可写入大小,
- if (num > 0)
- {
- if (num > count)
- {
- num = count;
- }
-
- Buffer.InternalBlockCopy(array, offset, _buffer, _writePos, num);//将array中的数据copy了一份到buffer中,不是立即写入,会在关闭流的时候再写入
- _writePos += num;//更新写入流的位置
- if (count == num)
- {
- return;//这种情况是剩余的写入大小大于指定的count
- }
-
- offset += num;
- count -= num;
- }
-
- if (_isAsync)
- {
- IAsyncResult asyncResult = BeginWriteCore(_buffer, 0, _writePos, null, null);
- EndWrite(asyncResult);
- }
- else
- {
- WriteCore(_buffer, 0, _writePos);//能走到这里,是因为count>num,此时buffer中数据已满,需要写入磁盘中
- }
-
- _writePos = 0;
- }
-
- if (count >= _bufferSize)//如果剩余的count或首次的count大于buffer大小,直接写入
- { //这里写入是先将buffer填满再写入,多余的直接写入
- WriteCore(array, offset, count);
- }
- else if (count != 0)
- {
- if (_buffer == null)
- {
- _buffer = new byte[_bufferSize];
- }
-
- Buffer.InternalBlockCopy(array, offset, _buffer, _writePos, count);//如果写入指定的count小于剩余的写入大小,只是将array中的数据copy了一份到buffer中,不是立即写入,会在关闭流的时候再写入
- _writePos = count;//更新写入流的位置
- }
- }
寻找位置
- public override long Position
- {
- [SecuritySafeCritical]
- get
- {
- if (_handle.IsClosed)
- {
- __Error.FileNotOpen();
- }
-
- if (!CanSeek)
- {
- __Error.SeekNotSupported();
- }
-
- if (_exposedHandle)//该值一般为false,get文件句柄时会被设置为true,此时文件流的位置,需要重新确定
- {
- VerifyOSHandlePosition();
- }
- //这里获取的不是真正的文件流的位置,而是上层调用者认为的流的位置
- return _pos + (_readPos - _readLen + _writePos);
- }
- set
- {
- if (value < 0)
- {
- throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- }
-
- if (_writePos > 0)//如果有需要写入的内容,会将内容先写入
- {
- FlushWrite(calledFromFinalizer: false);
- }
-
- _readPos = 0;
- _readLen = 0;
- Seek(value, SeekOrigin.Begin);//Position属性表示以流开始为起点的位置
- }
- }
-
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- if (origin < SeekOrigin.Begin || origin > SeekOrigin.End)
- {
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidSeekOrigin"));
- }
-
- if (_handle.IsClosed)
- {
- __Error.FileNotOpen();
- }
-
- if (!CanSeek)
- {
- __Error.SeekNotSupported();
- }
-
- if (_writePos > 0)
- {
- FlushWrite(calledFromFinalizer: false);
- }
- else if (origin == SeekOrigin.Current)
- {
- offset -= _readLen - _readPos;//如果以当前为起点,_readPos表示FilsStream的buffer的Pos,而不是文件流的真正的Position
- } //offset表示调用者认为的Position,(_readLen - _readPos)表示文件流真正的Position和调用者认为的Position之间的差值
-
- if (_exposedHandle)
- {
- VerifyOSHandlePosition();//实际上时调用SeekCore(0L, SeekOrigin.Current),重新定位下文件流的位置
- }
-
- long num = _pos + (_readPos - _readLen);//计算出来的文件流的真正位置
- long num2 = SeekCore(offset, origin);//重新定位文件流的位置
- if (_appendStart != -1 && num2 < _appendStart)
- {
- SeekCore(num, SeekOrigin.Begin);
- throw new IOException(Environment.GetResourceString("IO.IO_SeekAppendOverwrite"));
- }
-
- if (_readLen > 0)//这表示之前已经读取了部分文件信息
- {
- if (num == num2)//一般是这种情况
- {
- if (_readPos > 0)//以readPos为分界线,把buffer中后面的数据拷贝到前面,这样readPos为0了,readLen减少了
- {
- Buffer.InternalBlockCopy(_buffer, _readPos, _buffer, 0, _readLen - _readPos);
- _readLen -= _readPos;
- _readPos = 0;
- }
-
- if (_readLen > 0)//恢复文件流的真正位置
- {
- SeekCore(_readLen, SeekOrigin.Current);
- }
- }
- else if (num - _readPos < num2 && num2 < num + _readLen - _readPos)//表示重新定位的文件流的位置小于计算出来的文件流的位置
- { //大于上次读取文件流时得位置
- int num3 = (int)(num2 - num);
- Buffer.InternalBlockCopy(_buffer, _readPos + num3, _buffer, 0, _readLen - (_readPos + num3));
- _readLen -= _readPos + num3;
- _readPos = 0;
- if (_readLen > 0)
- {
- SeekCore(_readLen, SeekOrigin.Current);
- }
- }
- else
- {
- _readPos = 0;
- _readLen = 0;
- }
- }
-
- return num2;
- }
- //可以看到Seek流程很复杂,为了提高性能,应该避免再读数据时比默认buffersize大,直接读到指定的array中,不要经过FileStream的buffer。
- //一定要避免写数据和读数据交叉进行
- //因为filsStream的设计考虑了通用,当我们按照一定的规范去使用时,可以减少很多为通用情况而做的耗费性能的设计
构造函数
只需要关注红色方框里的两个构造函数即可,其他的都是重载。

memorystream也有一个buffer来缓存数据,在new的时候可以指定这个buffer的大小,那么这个buffer的实例化在new的时候完成,如果在写数据时这个buffer的大小不够用,则会自动扩容。
也可以自己实例化一个buffer,并在new的时候通过index和count来指定memorystream可以用这个buffer的哪一部分。通过这种方式new时,如果写数据时大小不够用,是不能扩容的。
writable表示是否可以写入
publiclyVisible表示是否可以拿到memorystream内部的buffer
方法
写入数据
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
- }
-
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- }
-
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- }
-
- if (buffer.Length - offset < count)
- {
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
- }
-
- if (!_isOpen)
- {
- __Error.StreamIsClosed();
- }
-
- EnsureWriteable();//确保可以写入,不能不能写入会报错,不继续执行了
- int num = _position + count; //计算加入全部写入时流的位置
- if (num < 0) //超出int可表示的最大值的检查,可以注意下,一般自己写代码时很少会做这种检查,虽然一般情况下也不需要
- { //MemoryStream的最大容量是int.MaxValue
- throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong"));
- }
-
- if (num > _length)//全部写入时流的位置大于buffer的长度,就需要扩容了
- {
- bool flag = _position > _length;
- if (num > _capacity && EnsureCapacity(num))
- {
- flag = false;
- }
-
- if (flag)//流的位置大于Buffer长度,需要清除多余的部分
- {
- Array.Clear(_buffer, _length, num - _length);
- }
-
- _length = num;
- }
-
- if (count <= 8 && buffer != _buffer) //当字节小于8时则一个个读
- {
- int num2 = count;
- while (--num2 >= 0)
- {
- _buffer[_position + num2] = buffer[offset + num2];
- }
- }
- else//将提供的buffer数据拷贝到MemoryStream的buffer种
- { //Buffer.BlockCopy比Array.Copy更快
- //https://stackoverflow.com/questions/1389821/array-copy-vs-buffer-blockcopy
- Buffer.InternalBlockCopy(buffer, offset, _buffer, _position, count);
- }
-
- _position = num;//更新流的位置
- }
-
-
- private bool EnsureCapacity(int value)
- {
- if (value < 0)
- {
- throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong"));
- }
-
- if (value > _capacity)
- {
- int num = value;
- if (num < 256)
- {
- num = 256;//容量小于256时,会被规范为256
- }
-
- if (num < _capacity * 2)
- {
- num = _capacity * 2;//两倍扩容
- }
-
- if ((uint)(_capacity * 2) > 2147483591u)//处理超限
- {
- num = ((value > 2147483591) ? value : 2147483591);
- }
-
- Capacity = num;
- return true;
- }
-
- return false;
- }
-
- public virtual int Capacity
- {
- [__DynamicallyInvokable]
- get
- {
- if (!_isOpen)
- {
- __Error.StreamIsClosed();
- }
-
- return _capacity - _origin;
- }
- [__DynamicallyInvokable]
- set
- {
- if (value < Length)
- {
- throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
- }
-
- if (!_isOpen)
- {
- __Error.StreamIsClosed();
- }
-
- if (!_expandable && value != Capacity)
- {
- __Error.MemoryStreamNotExpandable();
- }
-
- if (!_expandable || value == _capacity)//new时指定了buffer就不能扩容了
- {
- return;
- }
-
- if (value > 0)
- {
- byte[] array = new byte[value];
- if (_length > 0)//扩容时会将原来的数据copy到新的buffer种
- {
- Buffer.InternalBlockCopy(_buffer, 0, array, 0, _length);
- }
-
- _buffer = array;
- }
- else
- {
- _buffer = null;
- }
-
- _capacity = value;
- }
- }
读取数据
- public override int Read([In][Out] byte[] buffer, int offset, int count)//理解了write后,read方法很简单
- {
- if (buffer == null)
- {
- throw new ArgumentNullException("buffer", Environment.GetResourceString("ArgumentNull_Buffer"));
- }
-
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- }
-
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
- }
-
- if (buffer.Length - offset < count)
- {
- throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
- }
-
- if (!_isOpen)
- {
- __Error.StreamIsClosed();
- }
-
- int num = _length - _position;
- if (num > count)
- {
- num = count;
- }
-
- if (num <= 0)
- {
- return 0;
- }
-
- if (num <= 8)
- {
- int num2 = num;
- while (--num2 >= 0)
- {
- buffer[offset + num2] = _buffer[_position + num2];
- }
- }
- else
- {
- Buffer.InternalBlockCopy(_buffer, _position, buffer, offset, num);//将数据拷贝到指定的buffer中
- }
-
- _position += num;//读完后,流的position增加
- return num;
- }
构造函数

Stream参数,FileStream、MemoryStream都继承自Stream,这里传递进来主要是要用这些Stream的buffer
Encoding 编码类型,默认是new UTF8Encoding()
leaveOpen:表示close时要不要把stream要不要保持打开,默认为false,会将stream也close
方法
- //可以每次写入实际是将数据写入Stream的buffer中,BinaryWriter将数据序列化了,这里只提供基本数据类型的序列化
- public virtual void Write(bool value)//写入bool
- {
- _buffer[0] = (byte)(value ? 1u : 0u);//bool也是byte
- OutStream.Write(_buffer, 0, 1);//BinaryWriter也有有个buffer,固定的长度,为16,之所以为16是因为有个decimal类型要有16个字节表示
- }
-
- public virtual void Write(byte value)//byte直接写入
- {
- OutStream.WriteByte(value);
- }
-
- public virtual void Write(byte[] buffer)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException("buffer");
- }
-
- OutStream.Write(buffer, 0, buffer.Length);//byte[]一样是直接写入到stream的buffer中
- }
-
- public virtual void Write(short value)
- {
- _buffer[0] = (byte)value;//先取到低八位
- _buffer[1] = (byte)(value >> 8);//右移取到高八位
- OutStream.Write(_buffer, 0, 2);
- }
-
- public virtual void Write(int value)
- {
- _buffer[0] = (byte)value;
- _buffer[1] = (byte)(value >> 8);
- _buffer[2] = (byte)(value >> 16);
- _buffer[3] = (byte)(value >> 24);
- OutStream.Write(_buffer, 0, 4);
- }
-
- public virtual void Write(long value)
- {
- _buffer[0] = (byte)value;
- _buffer[1] = (byte)(value >> 8);
- _buffer[2] = (byte)(value >> 16);
- _buffer[3] = (byte)(value >> 24);
- _buffer[4] = (byte)(value >> 32);
- _buffer[5] = (byte)(value >> 40);
- _buffer[6] = (byte)(value >> 48);
- _buffer[7] = (byte)(value >> 56);
- OutStream.Write(_buffer, 0, 8);
- }
-
- public unsafe virtual void Write(string value)
- {
- if (value == null)
- {
- throw new ArgumentNullException("value");
- }
-
- int byteCount = _encoding.GetByteCount(value);
- Write7BitEncodedInt(byteCount);//会先写入字符串的byte长度
- if (_largeByteBuffer == null)
- {
- _largeByteBuffer = new byte[256];//先尝试用一个256长度的Buffer做首次尝试
- _maxChars = _largeByteBuffer.Length / _encoding.GetMaxByteCount(1);//获取该编码格式下,最大的字符需要多少byte,maxChar表示largeByteBuffer最多可以容纳多少个字符
- }
-
- if (byteCount <= _largeByteBuffer.Length)//小256,就直接将编码得到的bytes放入largeByteBuffer,再copy到Stream的buffer中
- {
- _encoding.GetBytes(value, 0, value.Length, _largeByteBuffer, 0);
- OutStream.Write(_largeByteBuffer, 0, byteCount);
- return;
- }
-
- int num = 0;
- int num2 = value.Length;
- while (num2 > 0)//字符串的长度大于128时,将字符串拆分转为bytes,分别写入largeByteBuffer
- {
- int num3 = (num2 > _maxChars) ? _maxChars : num2;
- if (num < 0 || num3 < 0 || checked(num + num3) > value.Length)
- {
- throw new ArgumentOutOfRangeException("charCount");
- }
-
- int bytes2;
- fixed (char* ptr = value)
- {
- fixed (byte* bytes = _largeByteBuffer)
- {
- //因为字符串不可修改,要使用指针读取,这个方法表示的意思和之前的_encoder.GetBytes是一样的,
- bytes2 = _encoder.GetBytes((char*)checked(unchecked((nuint)ptr) + unchecked((nuint)checked(unchecked((nint)num) * (nint)2))), num3, bytes, _largeByteBuffer.Length, num3 == num2);
- }
- }
-
- OutStream.Write(_largeByteBuffer, 0, bytes2);
- num += num3;
- num2 -= num3;
- }
- }
-
-
- protected void Write7BitEncodedInt(int value)//用于将整数值编码为7位压缩格式并写入流中。
- { //它通常用于数据序列化或网络通信过程中,以减小整数值的存储空间和传输开销。编码过程中,整数值按照7位的块进行分割,并将每个块的最高位设置为1,表示后面还有更多的块。每个块的其余7位用于存储整数值的一部分。
- uint num; //这样,较小的整数值可以用较少的字节进行编码,而较大的整数值则需要更多的字节。
- for (num = (uint)value; num >= 128; num >>= 7) //这种方式相比于之前的Write(int value),会减少存储空间
- {
- Write((byte)(num | 0x80));//0x80是 1000 0000,这里直接舍去了num的后七位
- }
-
- Write((byte)num);
- }
构造函数

方法
- //可以发现真正读数据都是Stream完成的,BinaryReader将读出来的数据反序列化了,这里只提供byte到基本数据类型的反序列化
- public virtual byte ReadByte()//读byte
- {
- if (m_stream == null)
- {
- __Error.FileNotOpen();
- }
-
- int num = m_stream.ReadByte();//实际调用的是Stream的ReadByte方法,最低读8位
- if (num == -1)
- {
- __Error.EndOfFile();
- }
-
- return (byte)num;
- }
-
- public virtual short ReadInt16()//读short
- {
- FillBuffer(2);//16/8=2
- return (short)(m_buffer[0] | (m_buffer[1] << 8));//低位在前面,高位在后面,这是小端模式存储
- }
-
- public virtual int ReadInt32()//读int
- {
- if (m_isMemoryStream)//new BinaryStream会判断下Stream是不是MemoryStream
- {
- if (m_stream == null)
- {
- __Error.FileNotOpen();
- }
-
- MemoryStream memoryStream = m_stream as MemoryStream;
- return memoryStream.InternalReadInt32();
- }
-
- FillBuffer(4);//32/8=4
- return m_buffer[0] | (m_buffer[1] << 8) | (m_buffer[2] << 16) | (m_buffer[3] << 24);
- }
-
- public unsafe virtual float ReadSingle()//读取float
- {
- FillBuffer(4);
- uint num = (uint)(m_buffer[0] | (m_buffer[1] << 8) | (m_buffer[2] << 16) | (m_buffer[3] << 24));
- return *(float*)(&num);
- }
-
- public unsafe virtual double ReadDouble()//读取double
- {
- FillBuffer(8);
- uint num = (uint)(m_buffer[0] | (m_buffer[1] << 8) | (m_buffer[2] << 16) | (m_buffer[3] << 24));
- uint num2 = (uint)(m_buffer[4] | (m_buffer[5] << 8) | (m_buffer[6] << 16) | (m_buffer[7] << 24));
- ulong num3 = ((ulong)num2 << 32) | num;
- return *(double*)(&num3);
- }
-
-
- public virtual string ReadString()
- {
- if (m_stream == null)
- {
- __Error.FileNotOpen();
- }
-
- int num = 0;
- int num2 = Read7BitEncodedInt();//读取字符串长度
- if (num2 < 0)
- {
- throw new IOException(Environment.GetResourceString("IO.IO_InvalidStringLen_Len", num2));
- }
-
- if (num2 == 0)
- {
- return string.Empty;
- }
-
- if (m_charBytes == null)
- {
- m_charBytes = new byte[128];//这里是存储读取到的字节数组
- }
-
- if (m_charBuffer == null)
- {
- m_charBuffer = new char[m_maxCharsSize];//这里存储的是字符数组 m_maxCharsSize = encoding.GetMaxCharCount(128);maxCharSize是该编码下128个字符的最大大小
- }
-
- StringBuilder stringBuilder = null;
- do
- {
- int count = (num2 - num > 128) ? 128 : (num2 - num);
- int num3 = m_stream.Read(m_charBytes, 0, count);
- if (num3 == 0)
- {
- __Error.EndOfFile();
- }
- //每次将charBytes数组中起始节点为0,数量为num3的数据解码放大charBuffer中,在charBuffer中的起始地址为0
- int chars = m_decoder.GetChars(m_charBytes, 0, num3, m_charBuffer, 0);
- if (num == 0 && num3 == num2)
- {
- return new string(m_charBuffer, 0, chars);//字符串长度小于128的就直接返回了
- }
-
- if (stringBuilder == null)
- {
- stringBuilder = StringBuilderCache.Acquire(Math.Min(num2, 360));
- }
-
- stringBuilder.Append(m_charBuffer, 0, chars);
- num += num3;
- }
- while (num < num2);
- return StringBuilderCache.GetStringAndRelease(stringBuilder);
- }
-
- protected internal int Read7BitEncodedInt()
- {
- int num = 0;
- int num2 = 0;
- byte b;
- do
- {
- if (num2 == 35)
- {
- throw new FormatException(Environment.GetResourceString("Format_Bad7BitInt32"));
- }
-
- b = ReadByte();
- num |= (b & 0x7F) << num2;
- num2 += 7;
- }
- while ((b & 0x80) != 0);
- return num;
- }