using System; using System.Threading; namespace Island.StandardLib.Storage { /// /// 提供一个线程安全的、可动态扩展、可垃圾回收且支持序列化的缓存区域 /// public class MultiSizeData : IStorable { byte[] Data; /// /// 读取位置 /// public int ReadPosition { get; set; } /// /// 未读取内容长度 /// public int ReadRemainEnd => Data.Length - ReadPosition; /// /// 读取内容和缓存起点的距离 /// public int ReadRemainBegin => ReadPosition; /// /// 写入位置 /// public int WritePosition { get; set; } /// /// 未写入内容长度,此值在默认应用下应为0 /// public int WriteRemainEnd => Data.Length - WritePosition; /// /// 写入内容和缓存起点的距离 /// public int WriteRemainBegin => WritePosition; /// /// 从这个值开始,向前的内存区域已经完成写入和读取操作,可被释放 /// public int FreePtr => ReadPosition > WritePosition ? WritePosition : ReadPosition; /// /// 当前缓存长度 /// public int Size => Data.Length; /// /// 初始化缓存区域,初始大小为0 /// public MultiSizeData() { Data = new byte[0]; lck_itio = new object(); lck_recvier = new object(); } object lck_itio, lck_recvier; /// /// 向缓存的任意位置写入数据,若长度不足则拓展缓存 /// /// 写入起点 /// 写入的内容 public void WriteAnyWhere(int begin, byte[] data) { lock (lck_itio) { if (Data.Length < begin + data.Length) { byte[] newData = new byte[begin + data.Length]; Array.Copy(Data, newData, Data.Length); Data = newData; } Array.Copy(data, 0, Data, begin, data.Length); } } /// /// 从缓存区域的任意位置读取数据,若当前不存在指定的区域则引发异常 /// /// 读取起点 /// 读取到的目标数组 /// 目标数组偏移量 /// 读取长度 public void ReadAnyWhere(int begin, byte[] writeTo, int offset, int size) { lock (lck_itio) { Array.Copy(Data, begin, writeTo, offset, size); } } /// /// 向缓存区域的最后写入位置追加内容,若长度不足则拓展缓存 /// /// 追加的数据 public void Write(byte[] data) { lock (lck_recvier) { WriteAnyWhere(WritePosition, data); WritePosition += data.Length; } } /// /// 从缓存区域的最后读取位置读取指定长度的内容,若当前缓存长度不足则等待 /// /// 读取到的目标数组 /// 目标数组偏移量 /// 读取长度 public void Read(byte[] buffer, int offset, int size) { while (ReadRemainEnd < size) Thread.Sleep(1); lock (lck_recvier) { ReadAnyWhere(ReadPosition, buffer, offset, size); ReadPosition += size; } } /// /// 释放当前已读写的缓存区域,并调整读取位置和写入位置 /// public void FreeUnused() { lock (lck_recvier) { lock (lck_itio) { int downSize = FreePtr; if (downSize == 0) return; byte[] newData = new byte[Size - downSize]; Array.Copy(Data, downSize, newData, 0, Size - downSize); ReadPosition -= downSize; WritePosition -= downSize; Data = newData; } } } public void ReadFromData(DataStorage data) { data.Read(out int read); ReadPosition = read; data.Read(out int write); WritePosition = write; Data = data.Read(); } public void WriteToData(DataStorage data) { lock (lck_itio) { data.Write(ReadPosition); data.Write(WritePosition); data.Write(Data); } } } }