You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1249 lines
40 KiB
1249 lines
40 KiB
|
3 months ago
|
//------------------------------------------------------------------------------
|
||
|
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||
|
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||
|
|
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||
|
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||
|
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||
|
|
// Github源代码仓库:https://github.com/RRQM
|
||
|
|
// API首页:https://www.yuque.com/rrqm/touchsocket/index
|
||
|
|
// 交流QQ群:234762506
|
||
|
|
// 感谢您的下载和使用
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
|
||
|
|
using System;
|
||
|
|
using System.Diagnostics;
|
||
|
|
using System.IO;
|
||
|
|
using System.Text;
|
||
|
|
using System.Threading;
|
||
|
|
|
||
|
|
namespace TouchSocket.Core
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 字节块流
|
||
|
|
/// </summary>
|
||
|
|
[DebuggerDisplay("Len={Len},Pos={Pos},Capacity={Capacity}")]
|
||
|
|
public ref partial struct ValueByteBlock
|
||
|
|
{
|
||
|
|
private static float m_ratio = 1.5f;
|
||
|
|
private readonly bool m_needDis;
|
||
|
|
private byte[] m_buffer;
|
||
|
|
private int m_dis;
|
||
|
|
private bool m_holding;
|
||
|
|
private long m_length;
|
||
|
|
private long m_position;
|
||
|
|
private bool m_using;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 构造函数
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="byteSize"></param>
|
||
|
|
/// <param name="equalSize"></param>
|
||
|
|
public ValueByteBlock(int byteSize = 1024 * 64, bool equalSize = false)
|
||
|
|
{
|
||
|
|
m_dis = 1;
|
||
|
|
m_needDis = true;
|
||
|
|
m_buffer = BytePool.Default.GetByteCore(byteSize, equalSize);
|
||
|
|
m_using = true;
|
||
|
|
m_length = 0;
|
||
|
|
m_holding = false;
|
||
|
|
m_position = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 实例化一个已知内存的对象。且该内存不会被回收。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bytes"></param>
|
||
|
|
public ValueByteBlock(byte[] bytes)
|
||
|
|
{
|
||
|
|
m_dis = 0;
|
||
|
|
m_needDis = false;
|
||
|
|
m_buffer = bytes ?? throw new ArgumentNullException(nameof(bytes));
|
||
|
|
m_length = bytes.Length;
|
||
|
|
m_using = true;
|
||
|
|
m_length = 0;
|
||
|
|
m_holding = false;
|
||
|
|
m_position = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 扩容增长比,默认为1.5,
|
||
|
|
/// min:1.5
|
||
|
|
/// </summary>
|
||
|
|
public static float Ratio
|
||
|
|
{
|
||
|
|
get => m_ratio;
|
||
|
|
set
|
||
|
|
{
|
||
|
|
if (value < 1.5)
|
||
|
|
{
|
||
|
|
value = 1.5f;
|
||
|
|
}
|
||
|
|
m_ratio = value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 字节实例
|
||
|
|
/// </summary>
|
||
|
|
public byte[] Buffer => m_buffer;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 仅当内存块可用,且<see cref="CanReadLen"/>>0时为True。
|
||
|
|
/// </summary>
|
||
|
|
public bool CanRead => m_using && CanReadLen > 0;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 还能读取的长度,计算为<see cref="Len"/>与<see cref="Pos"/>的差值。
|
||
|
|
/// </summary>
|
||
|
|
public int CanReadLen => Len - Pos;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 还能读取的长度,计算为<see cref="Len"/>与<see cref="Pos"/>的差值。
|
||
|
|
/// </summary>
|
||
|
|
public long CanReadLength => m_length - m_position;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 支持查找
|
||
|
|
/// </summary>
|
||
|
|
public bool CanSeek => m_using;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 可写入
|
||
|
|
/// </summary>
|
||
|
|
public bool CanWrite => m_using;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 容量
|
||
|
|
/// </summary>
|
||
|
|
public int Capacity => m_buffer.Length;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 空闲长度,准确掌握该值,可以避免内存扩展,计算为<see cref="Capacity"/>与<see cref="Pos"/>的差值。
|
||
|
|
/// </summary>
|
||
|
|
public int FreeLength => Capacity - Pos;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 表示持续性持有,为True时,Dispose将调用无效。
|
||
|
|
/// </summary>
|
||
|
|
public bool Holding => m_holding;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Int真实长度
|
||
|
|
/// </summary>
|
||
|
|
public int Len => (int)m_length;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 真实长度
|
||
|
|
/// </summary>
|
||
|
|
public long Length => m_length;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// int型流位置
|
||
|
|
/// </summary>
|
||
|
|
public int Pos
|
||
|
|
{
|
||
|
|
get => (int)m_position;
|
||
|
|
set => m_position = value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 流位置
|
||
|
|
/// </summary>
|
||
|
|
public long Position
|
||
|
|
{
|
||
|
|
get => m_position;
|
||
|
|
set => m_position = value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 使用状态
|
||
|
|
/// </summary>
|
||
|
|
public bool Using => m_using;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 创建一个来自于内存池的成员。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="byteSize"></param>
|
||
|
|
/// <param name="equalSize"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public static ValueByteBlock Create(int byteSize = 1024 * 64, bool equalSize = false)
|
||
|
|
{
|
||
|
|
return new ValueByteBlock(byteSize, equalSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 直接完全释放,游离该对象,然后等待GC
|
||
|
|
/// </summary>
|
||
|
|
public void AbsoluteDispose()
|
||
|
|
{
|
||
|
|
if (Interlocked.Decrement(ref m_dis) == 0)
|
||
|
|
{
|
||
|
|
Dis();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 清空所有内存数据
|
||
|
|
/// </summary>
|
||
|
|
/// <exception cref="ObjectDisposedException">内存块已释放</exception>
|
||
|
|
public void Clear()
|
||
|
|
{
|
||
|
|
if (!m_using)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException(nameof(ValueByteBlock));
|
||
|
|
}
|
||
|
|
Array.Clear(m_buffer, 0, m_buffer.Length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public void Dispose()
|
||
|
|
{
|
||
|
|
if (m_holding)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_needDis)
|
||
|
|
{
|
||
|
|
if (Interlocked.Decrement(ref m_dis) == 0)
|
||
|
|
{
|
||
|
|
BytePool.Default.Recycle(m_buffer);
|
||
|
|
Dis();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 释放当前内存到指定内存池
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bytePool"></param>
|
||
|
|
public void Dispose(BytePool bytePool)
|
||
|
|
{
|
||
|
|
if (m_holding)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (m_needDis)
|
||
|
|
{
|
||
|
|
if (Interlocked.Decrement(ref m_dis) == 0)
|
||
|
|
{
|
||
|
|
bytePool.Recycle(m_buffer);
|
||
|
|
Dis();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 读取数据,然后递增Pos
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ObjectDisposedException"></exception>
|
||
|
|
public int Read(byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
if (!m_using)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException(nameof(ValueByteBlock));
|
||
|
|
}
|
||
|
|
int len = m_length - m_position > length ? length : CanReadLen;
|
||
|
|
Array.Copy(m_buffer, m_position, buffer, offset, len);
|
||
|
|
m_position += len;
|
||
|
|
return len;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 读取数据,然后递增Pos
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public int Read(byte[] buffer)
|
||
|
|
{
|
||
|
|
return Read(buffer, 0, buffer.Length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 读取数据,然后递增Pos
|
||
|
|
/// </summary>
|
||
|
|
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public int Read(out byte[] buffer, int length)
|
||
|
|
{
|
||
|
|
buffer = new byte[length];
|
||
|
|
return Read(buffer, 0, buffer.Length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="byte"/>值
|
||
|
|
/// </summary>
|
||
|
|
public int ReadByte()
|
||
|
|
{
|
||
|
|
byte value = m_buffer[m_position];
|
||
|
|
m_position++;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 将内存块初始化到刚申请的状态。
|
||
|
|
/// <para>仅仅重置<see cref="Position"/>和<see cref="Length"/>属性。</para>
|
||
|
|
/// </summary>
|
||
|
|
/// <exception cref="ObjectDisposedException">内存块已释放</exception>
|
||
|
|
public void Reset()
|
||
|
|
{
|
||
|
|
if (!m_using)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException(nameof(ValueByteBlock));
|
||
|
|
}
|
||
|
|
m_position = 0;
|
||
|
|
m_length = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 设置流位置
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="origin"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ObjectDisposedException"></exception>
|
||
|
|
public long Seek(long offset, SeekOrigin origin)
|
||
|
|
{
|
||
|
|
if (!m_using)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException(nameof(ValueByteBlock));
|
||
|
|
}
|
||
|
|
switch (origin)
|
||
|
|
{
|
||
|
|
case SeekOrigin.Begin:
|
||
|
|
m_position = offset;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SeekOrigin.Current:
|
||
|
|
m_position += offset;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SeekOrigin.End:
|
||
|
|
m_position = m_length + offset;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
return m_position;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 移动游标
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="position"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public void Seek(int position)
|
||
|
|
{
|
||
|
|
Position = position;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 设置游标到末位
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public void SeekToEnd()
|
||
|
|
{
|
||
|
|
Position = Length;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 设置游标到首位
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public void SeekToStart()
|
||
|
|
{
|
||
|
|
Position = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 重新设置容量
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="size">新尺寸</param>
|
||
|
|
/// <param name="retainedData">是否保留元数据</param>
|
||
|
|
/// <exception cref="ObjectDisposedException"></exception>
|
||
|
|
public void SetCapacity(int size, bool retainedData = false)
|
||
|
|
{
|
||
|
|
if (!m_using)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException("ValueByteBlock");
|
||
|
|
}
|
||
|
|
byte[] bytes = new byte[size];
|
||
|
|
|
||
|
|
if (retainedData)
|
||
|
|
{
|
||
|
|
Array.Copy(m_buffer, 0, bytes, 0, m_buffer.Length);
|
||
|
|
}
|
||
|
|
if (m_needDis)
|
||
|
|
{
|
||
|
|
BytePool.Default.Recycle(m_buffer);
|
||
|
|
}
|
||
|
|
m_buffer = bytes;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 设置持续持有属性,当为True时,调用Dispose会失效,表示该对象将长期持有,直至设置为False。
|
||
|
|
/// 当为False时,会自动调用Dispose。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="holding"></param>
|
||
|
|
/// <exception cref="ObjectDisposedException"></exception>
|
||
|
|
public void SetHolding(bool holding)
|
||
|
|
{
|
||
|
|
if (!m_using)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException("ValueByteBlock");
|
||
|
|
}
|
||
|
|
m_holding = holding;
|
||
|
|
if (!holding)
|
||
|
|
{
|
||
|
|
Dispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 设置实际长度
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <exception cref="ObjectDisposedException"></exception>
|
||
|
|
public void SetLength(long value)
|
||
|
|
{
|
||
|
|
if (!m_using)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException("ValueByteBlock");
|
||
|
|
}
|
||
|
|
if (value > m_buffer.Length)
|
||
|
|
{
|
||
|
|
throw new Exception("设置值超出容量");
|
||
|
|
}
|
||
|
|
m_length = value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从指定位置转化到指定长度的有效内存
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public byte[] ToArray(int offset, int length)
|
||
|
|
{
|
||
|
|
if (!m_using)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException("ValueByteBlock");
|
||
|
|
}
|
||
|
|
byte[] buffer = new byte[length];
|
||
|
|
Array.Copy(m_buffer, offset, buffer, 0, buffer.Length);
|
||
|
|
return buffer;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 转换为有效内存
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public byte[] ToArray()
|
||
|
|
{
|
||
|
|
return ToArray(0, Len);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从指定位置转化到有效内存
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
/// <exception cref="ObjectDisposedException"></exception>
|
||
|
|
public byte[] ToArray(int offset)
|
||
|
|
{
|
||
|
|
return ToArray(offset, Len - offset);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 转换为UTF-8字符
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public override string ToString()
|
||
|
|
{
|
||
|
|
return ToString(0, Len);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 转换为UTF-8字符
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="offset">偏移量</param>
|
||
|
|
/// <param name="length">长度</param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public string ToString(int offset, int length)
|
||
|
|
{
|
||
|
|
if (!m_using)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException("ValueByteBlock");
|
||
|
|
}
|
||
|
|
return Encoding.UTF8.GetString(m_buffer, offset, length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 转换为UTF-8字符
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="offset">偏移量</param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public string ToString(int offset)
|
||
|
|
{
|
||
|
|
if (!m_using)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException("ValueByteBlock");
|
||
|
|
}
|
||
|
|
return Encoding.UTF8.GetString(m_buffer, offset, Len - offset);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="count"></param>
|
||
|
|
/// <exception cref="ObjectDisposedException"></exception>
|
||
|
|
public void Write(byte[] buffer, int offset, int count)
|
||
|
|
{
|
||
|
|
if (count == 0)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (!m_using)
|
||
|
|
{
|
||
|
|
throw new ObjectDisposedException("ValueByteBlock");
|
||
|
|
}
|
||
|
|
if (m_buffer.Length - m_position < count)
|
||
|
|
{
|
||
|
|
int need = m_buffer.Length + count - ((int)(m_buffer.Length - m_position));
|
||
|
|
int lend = m_buffer.Length;
|
||
|
|
while (need > lend)
|
||
|
|
{
|
||
|
|
lend = (int)(lend * m_ratio);
|
||
|
|
}
|
||
|
|
SetCapacity(lend, true);
|
||
|
|
}
|
||
|
|
Array.Copy(buffer, offset, m_buffer, m_position, count);
|
||
|
|
m_position += count;
|
||
|
|
m_length = Math.Max(m_position, m_length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <exception cref="NotImplementedException"></exception>
|
||
|
|
public void Write(byte[] buffer)
|
||
|
|
{
|
||
|
|
Write(buffer, 0, buffer.Length);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void Dis()
|
||
|
|
{
|
||
|
|
m_holding = false;
|
||
|
|
m_using = false;
|
||
|
|
m_position = 0;
|
||
|
|
m_length = 0;
|
||
|
|
m_buffer = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
#region BytesPackage
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个独立的<see cref="byte"/>数组包
|
||
|
|
/// </summary>
|
||
|
|
public byte[] ReadBytesPackage()
|
||
|
|
{
|
||
|
|
byte status = (byte)ReadByte();
|
||
|
|
if (status == 0)
|
||
|
|
{
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
int length = ReadInt32();
|
||
|
|
byte[] data = new byte[length];
|
||
|
|
Array.Copy(Buffer, Pos, data, 0, length);
|
||
|
|
Pos += length;
|
||
|
|
return data;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 尝试获取数据包信息,方便从Buffer操作数据
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="pos"></param>
|
||
|
|
/// <param name="len"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool TryReadBytesPackageInfo(out int pos, out int len)
|
||
|
|
{
|
||
|
|
byte status = (byte)ReadByte();
|
||
|
|
if (status == 0)
|
||
|
|
{
|
||
|
|
pos = 0;
|
||
|
|
len = 0;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
len = ReadInt32();
|
||
|
|
pos = Pos;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入一个独立的<see cref="byte"/>数组包,值可以为null。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
public void WriteBytesPackage(byte[] value, int offset, int length)
|
||
|
|
{
|
||
|
|
if (value == null)
|
||
|
|
{
|
||
|
|
Write((byte)0);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
Write((byte)1);
|
||
|
|
Write(length);
|
||
|
|
Write(value, offset, length);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入一个独立的<see cref="byte"/>数组包。值可以为null。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
public void WriteBytesPackage(byte[] value)
|
||
|
|
{
|
||
|
|
if (value == null)
|
||
|
|
{
|
||
|
|
WriteBytesPackage(value, 0, 0);
|
||
|
|
}
|
||
|
|
WriteBytesPackage(value, 0, value.Length);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion BytesPackage
|
||
|
|
|
||
|
|
#region Int32
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="int"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public int ReadInt32(bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
int value;
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: value = TouchSocketBitConverter.BigEndian.ToInt32(Buffer, Pos); break;
|
||
|
|
case false: value = TouchSocketBitConverter.LittleEndian.ToInt32(Buffer, Pos); break;
|
||
|
|
default: value = TouchSocketBitConverter.Default.ToInt32(Buffer, Pos); break;
|
||
|
|
}
|
||
|
|
m_position += 4;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="int"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public void Write(int value, bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break;
|
||
|
|
case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break;
|
||
|
|
default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Int32
|
||
|
|
|
||
|
|
#region Int16
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="short"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public short ReadInt16(bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
short value;
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: value = TouchSocketBitConverter.BigEndian.ToInt16(Buffer, Pos); break;
|
||
|
|
case false: value = TouchSocketBitConverter.LittleEndian.ToInt16(Buffer, Pos); break;
|
||
|
|
default: value = TouchSocketBitConverter.Default.ToInt16(Buffer, Pos); break;
|
||
|
|
}
|
||
|
|
Pos += 2;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="short"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public void Write(short value, bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break;
|
||
|
|
case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break;
|
||
|
|
default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Int16
|
||
|
|
|
||
|
|
#region Int64
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="long"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public long ReadInt64(bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
long value;
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: value = TouchSocketBitConverter.BigEndian.ToInt64(Buffer, Pos); break;
|
||
|
|
case false: value = TouchSocketBitConverter.LittleEndian.ToInt64(Buffer, Pos); break;
|
||
|
|
default: value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos); break;
|
||
|
|
}
|
||
|
|
Pos += 8;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="long"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public void Write(long value, bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break;
|
||
|
|
case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break;
|
||
|
|
default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Int64
|
||
|
|
|
||
|
|
#region Boolean
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="bool"/>值
|
||
|
|
/// </summary>
|
||
|
|
public bool ReadBoolean()
|
||
|
|
{
|
||
|
|
bool value = TouchSocketBitConverter.Default.ToBoolean(Buffer, Pos);
|
||
|
|
Pos += 1;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="bool"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
public void Write(bool value)
|
||
|
|
{
|
||
|
|
Write(TouchSocketBitConverter.Default.GetBytes(value));
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Boolean
|
||
|
|
|
||
|
|
#region Byte
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="byte"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public void Write(byte value)
|
||
|
|
{
|
||
|
|
Write(new byte[] { value }, 0, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Byte
|
||
|
|
|
||
|
|
#region String
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="string"/>值
|
||
|
|
/// </summary>
|
||
|
|
public string ReadString()
|
||
|
|
{
|
||
|
|
int len = this.ReadInt32();
|
||
|
|
if (len < 0)
|
||
|
|
{
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
string str = Encoding.UTF8.GetString(Buffer, Pos, len);
|
||
|
|
Pos += len;
|
||
|
|
return str;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="string"/>值。值可以为null,或者空。
|
||
|
|
/// <para>注意:该操作不具备通用性,读取时必须使用ReadString。或者得先做出判断,由默认端序的int32值标识,具体如下:</para>
|
||
|
|
/// <list type="bullet">
|
||
|
|
/// <item>小于0,表示字符串为null</item>
|
||
|
|
/// <item>等于0,表示字符串为""</item>
|
||
|
|
/// <item>大于0,表示字符串在utf-8编码下的字节长度。</item>
|
||
|
|
/// </list>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
public void Write(string value)
|
||
|
|
{
|
||
|
|
if (value == null)
|
||
|
|
{
|
||
|
|
Write(-1);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
byte[] buffer = Encoding.UTF8.GetBytes(value);
|
||
|
|
Write(buffer.Length);
|
||
|
|
Write(buffer);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="string"/>值。值必须为有效值。可通用解析。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="encoding"></param>
|
||
|
|
public void WriteString(string value, Encoding encoding = null)
|
||
|
|
{
|
||
|
|
Write((encoding ?? Encoding.UTF8).GetBytes(value));
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion String
|
||
|
|
|
||
|
|
#region Char
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="char"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public char ReadChar(bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
char value;
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: value = TouchSocketBitConverter.BigEndian.ToChar(Buffer, Pos); break;
|
||
|
|
case false: value = TouchSocketBitConverter.LittleEndian.ToChar(Buffer, Pos); break;
|
||
|
|
default: value = TouchSocketBitConverter.Default.ToChar(Buffer, Pos); break;
|
||
|
|
}
|
||
|
|
Pos += 2;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="char"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public void Write(char value, bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break;
|
||
|
|
case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break;
|
||
|
|
default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Char
|
||
|
|
|
||
|
|
#region Double
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="double"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public double ReadDouble(bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
double value;
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: value = TouchSocketBitConverter.BigEndian.ToDouble(Buffer, Pos); break;
|
||
|
|
case false: value = TouchSocketBitConverter.LittleEndian.ToDouble(Buffer, Pos); break;
|
||
|
|
default: value = TouchSocketBitConverter.Default.ToDouble(Buffer, Pos); break;
|
||
|
|
}
|
||
|
|
Pos += 8;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="double"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public void Write(double value, bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break;
|
||
|
|
case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break;
|
||
|
|
default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Double
|
||
|
|
|
||
|
|
#region Float
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="float"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public float ReadFloat(bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
float value;
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: value = TouchSocketBitConverter.BigEndian.ToSingle(Buffer, Pos); break;
|
||
|
|
case false: value = TouchSocketBitConverter.LittleEndian.ToSingle(Buffer, Pos); break;
|
||
|
|
default: value = TouchSocketBitConverter.Default.ToSingle(Buffer, Pos); break;
|
||
|
|
}
|
||
|
|
Pos += 4;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="float"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public void Write(float value, bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break;
|
||
|
|
case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break;
|
||
|
|
default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Float
|
||
|
|
|
||
|
|
#region UInt16
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="ushort"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public ushort ReadUInt16(bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
ushort value;
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: value = TouchSocketBitConverter.BigEndian.ToUInt16(Buffer, Pos); break;
|
||
|
|
case false: value = TouchSocketBitConverter.LittleEndian.ToUInt16(Buffer, Pos); break;
|
||
|
|
default: value = TouchSocketBitConverter.Default.ToUInt16(Buffer, Pos); break;
|
||
|
|
}
|
||
|
|
Pos += 2;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="ushort"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public void Write(ushort value, bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break;
|
||
|
|
case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break;
|
||
|
|
default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion UInt16
|
||
|
|
|
||
|
|
#region UInt32
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="uint"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public uint ReadUInt32(bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
uint value;
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: value = TouchSocketBitConverter.BigEndian.ToUInt32(Buffer, Pos); break;
|
||
|
|
case false: value = TouchSocketBitConverter.LittleEndian.ToUInt32(Buffer, Pos); break;
|
||
|
|
default: value = TouchSocketBitConverter.Default.ToUInt32(Buffer, Pos); break;
|
||
|
|
}
|
||
|
|
Pos += 4;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="uint"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public void Write(uint value, bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break;
|
||
|
|
case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break;
|
||
|
|
default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion UInt32
|
||
|
|
|
||
|
|
#region UInt64
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="ulong"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public ulong ReadUInt64(bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
ulong value;
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: value = TouchSocketBitConverter.BigEndian.ToUInt64(Buffer, Pos); break;
|
||
|
|
case false: value = TouchSocketBitConverter.LittleEndian.ToUInt64(Buffer, Pos); break;
|
||
|
|
default: value = TouchSocketBitConverter.Default.ToUInt64(Buffer, Pos); break;
|
||
|
|
}
|
||
|
|
Pos += 8;
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="ulong"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="bigEndian">是否为指定大端编码。允许true(大端),false(小端),null(默认端序)三种赋值。默认为null。</param>
|
||
|
|
public void Write(ulong value, bool? bigEndian = null)
|
||
|
|
{
|
||
|
|
switch (bigEndian)
|
||
|
|
{
|
||
|
|
case true: Write(TouchSocketBitConverter.BigEndian.GetBytes(value)); break;
|
||
|
|
case false: Write(TouchSocketBitConverter.LittleEndian.GetBytes(value)); break;
|
||
|
|
default: Write(TouchSocketBitConverter.Default.GetBytes(value)); break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion UInt64
|
||
|
|
|
||
|
|
#region Null
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个标识值,判断是否为null。
|
||
|
|
/// </summary>
|
||
|
|
public bool ReadIsNull()
|
||
|
|
{
|
||
|
|
var status = ReadByte();
|
||
|
|
if (status == 0)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
else if (status == 1)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
throw new Exception("标识既非Null,也非NotNull,可能是流位置发生了错误。");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 判断该值是否为Null,然后写入标识值
|
||
|
|
/// </summary>
|
||
|
|
public void WriteIsNull<T>(T t) where T : class
|
||
|
|
{
|
||
|
|
if (t == null)
|
||
|
|
{
|
||
|
|
WriteNull();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
WriteNotNull();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入一个标识非Null值
|
||
|
|
/// </summary>
|
||
|
|
public void WriteNotNull()
|
||
|
|
{
|
||
|
|
Write((byte)1);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入一个标识Null值
|
||
|
|
/// </summary>
|
||
|
|
public void WriteNull()
|
||
|
|
{
|
||
|
|
Write((byte)0);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Null
|
||
|
|
|
||
|
|
#region DateTime
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="DateTime"/>值
|
||
|
|
/// </summary>
|
||
|
|
public DateTime ReadDateTime()
|
||
|
|
{
|
||
|
|
long value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos);
|
||
|
|
Pos += 8;
|
||
|
|
return DateTime.FromBinary(value);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="DateTime"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
public void Write(DateTime value)
|
||
|
|
{
|
||
|
|
Write(TouchSocketBitConverter.Default.GetBytes(value.ToBinary()));
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion DateTime
|
||
|
|
|
||
|
|
#region TimeSpan
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个<see cref="TimeSpan"/>值
|
||
|
|
/// </summary>
|
||
|
|
public TimeSpan ReadTimeSpan()
|
||
|
|
{
|
||
|
|
long value = TouchSocketBitConverter.Default.ToInt64(Buffer, Pos);
|
||
|
|
Pos += 8;
|
||
|
|
return TimeSpan.FromTicks(value);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="TimeSpan"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
public void Write(TimeSpan value)
|
||
|
|
{
|
||
|
|
Write(TouchSocketBitConverter.Default.GetBytes(value.Ticks));
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion TimeSpan
|
||
|
|
|
||
|
|
#region Object
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 从当前流位置读取一个泛型值
|
||
|
|
/// </summary>
|
||
|
|
/// <typeparam name="T"></typeparam>
|
||
|
|
/// <param name="serializationType"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public T ReadObject<T>(SerializationType serializationType = SerializationType.FastBinary)
|
||
|
|
{
|
||
|
|
int length = ReadInt32();
|
||
|
|
|
||
|
|
if (length == 0)
|
||
|
|
{
|
||
|
|
return default;
|
||
|
|
}
|
||
|
|
|
||
|
|
T obj;
|
||
|
|
|
||
|
|
switch (serializationType)
|
||
|
|
{
|
||
|
|
case SerializationType.FastBinary:
|
||
|
|
{
|
||
|
|
obj = SerializeConvert.FastBinaryDeserialize<T>(Buffer, Pos);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SerializationType.Json:
|
||
|
|
{
|
||
|
|
string jsonString = Encoding.UTF8.GetString(Buffer, Pos, length);
|
||
|
|
obj = SerializeConvert.JsonDeserializeFromString<T>(jsonString);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SerializationType.Xml:
|
||
|
|
{
|
||
|
|
string jsonString = Encoding.UTF8.GetString(Buffer, Pos, length);
|
||
|
|
obj = SerializeConvert.XmlDeserializeFromString<T>(jsonString);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SerializationType.SystemBinary:
|
||
|
|
{
|
||
|
|
obj = SerializeConvert.BinaryDeserialize<T>(Buffer, Pos, length);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
throw new Exception("未定义的序列化类型");
|
||
|
|
}
|
||
|
|
|
||
|
|
Pos += length;
|
||
|
|
return obj;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 写入<see cref="object"/>值
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="serializationType"></param>
|
||
|
|
public void WriteObject(object value, SerializationType serializationType = SerializationType.FastBinary)
|
||
|
|
{
|
||
|
|
if (value == null)
|
||
|
|
{
|
||
|
|
Write(0);
|
||
|
|
}
|
||
|
|
byte[] data;
|
||
|
|
switch (serializationType)
|
||
|
|
{
|
||
|
|
case SerializationType.FastBinary:
|
||
|
|
{
|
||
|
|
data = SerializeConvert.FastBinarySerialize(value);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SerializationType.Json:
|
||
|
|
{
|
||
|
|
data = SerializeConvert.JsonSerializeToBytes(value);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SerializationType.Xml:
|
||
|
|
{
|
||
|
|
data = Encoding.UTF8.GetBytes(SerializeConvert.XmlSerializeToString(value));
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case SerializationType.SystemBinary:
|
||
|
|
{
|
||
|
|
data = SerializeConvert.BinarySerialize(value);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
throw new Exception("未定义的序列化类型");
|
||
|
|
}
|
||
|
|
|
||
|
|
Write(data.Length);
|
||
|
|
Write(data);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Object
|
||
|
|
}
|
||
|
|
}
|