可以快速读写二进制文件
调用示例如下
static void Main(string[] args)
{
string targetFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "test.b2f");
using (var writer = new IdxInfoWriter(targetFile))
{
for (int i = 0; i < 10; i++)
{
writer.AppendItem(new IdxInfo
{
DataLength = i + 100,
Offset = 0,
Time = DateTime.Now,
});
}
}
using (var reader = new IdxInfoReader(targetFile))
{
var all = reader.GetFileResult();
all?.ForEach(f =>
{
Console.WriteLine($"Time:{f.Time},offset:{f.Offset},Datalength:{f.DataLength}");
});
}
}
class IdxInfoWriter : BaseBinaryFileWriter<IdxInfo>
{
public IdxInfoWriter(string file) : base(file)
{
}
}
class IdxInfoReader : BaseBinaryFileReader<IdxInfo>
{
public IdxInfoReader(string file) : base(file)
{
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct IdxInfo
{
public DateTime Time { set; get; }
public long Offset { set; get; }
public int DataLength { set; get; }
}
读取类:::
public abstract class BaseBinaryFileReader<T> : IDisposable where T : struct
{
protected uint HeaderSize { set; get; }
protected BinaryReader m_BinaryReader;
protected readonly uint m_ItemSize;
public uint ItemSize { get { return m_ItemSize; } }
protected readonly string m_File;
public BaseBinaryFileReader(string file, bool isReadOnly = false)
{
if (string.IsNullOrEmpty(file) || !File.Exists(file))
{
throw new FileNotFoundException($"{file}");
}
m_BinaryReader = new BinaryReader(GetFileStream(file, isReadOnly));
if (m_BinaryReader == null)
{
throw new ArgumentNullException();
}
m_ItemSize = (uint)Marshal.SizeOf(typeof(T));
m_File = file;
}
public BaseBinaryFileReader(string file, uint headSize, bool isReadOnly = false) : this(file, isReadOnly)
{
HeaderSize = headSize;
}
public static Stream GetFileStream(string sourceFile, bool isOnlyRead = false)
{
if (string.IsNullOrEmpty(sourceFile))
{
throw new ArgumentNullException();
}
try
{
if (isOnlyRead)
{
//只读文件
return new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read);
}
else
{
//可读取正在写入的文件
return new FileStream(sourceFile, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
}
}
catch (Exception)
{
//只读文件
return new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read);
}
}
/// <summary>
/// 获取点的总数量
/// </summary>
/// <returns></returns>
public uint GetTotalPoint()
{
if (m_BinaryReader == null)
{
return 0;
}
return (uint)((m_BinaryReader.BaseStream.Length - HeaderSize) / m_ItemSize);
}
protected const int PatchReadMinCount = 100;
/// <summary>
/// 按文件实际数量读取
/// </summary>
/// <param name="skipCount">跳过的点数</param>
/// <param name="takeCount">要取到的点数</param>
/// <param name="totalCount">总点数</param>
/// <returns></returns>
public virtual List<T> GetFileResult(uint skipCount = 0, uint takeCount = uint.MaxValue)
{
var res = new List<T>();
var totalCount = GetTotalPoint();
if (skipCount < totalCount)
{
ReadItems(res, skipCount, takeCount);
}
return res;
}
public virtual List<BinaryItemDetail<T>> GetFileResultDetail(uint skipCount, uint takeCount)
{
var res = new List<BinaryItemDetail<T>>();
var totalCount = GetTotalPoint();
if (skipCount < totalCount)
{
ReadItems(res, skipCount, takeCount);
}
return res;
}
/// <summary>
/// 读取文件
/// </summary>
/// <param name="res"></param>
/// <param name="skipCount">跳过的点数</param>
/// <param name="takeCount">要取的点数</param>
protected virtual void ReadItems(List<BinaryItemDetail<T>> res, uint skipCount, uint takeCount)
{
if (takeCount == 0)
{
return;
}
long tarPos = HeaderSize;
tarPos += m_ItemSize * skipCount;
if (!CanReadNext(tarPos))
{
return;
}
int buffSize = (int)(m_ItemSize * Math.Min(PatchReadMinCount, takeCount));
byte[] buffArr = new byte[buffSize];
var fs = m_BinaryReader.BaseStream;
fs.Position = tarPos;
while (true)
{
if (res.Count >= takeCount)
{
break;
}
if (!CanReadNext(fs.Position))
{
break;
}
var startPos = m_BinaryReader.BaseStream.Position;
var readLen = m_BinaryReader.Read(buffArr, 0, buffSize);
if (readLen == 0)
{
break;
}
var items = ByteHelper.BytesToStruct<T>(buffArr, 0, readLen);
foreach (var item in items)
{
res.Add(new BinaryItemDetail<T> { Offset = startPos, Content = item });
if (res.Count >= takeCount)
{
break;
}
startPos += m_ItemSize;
}
}
}
protected virtual void ReadItems(List<T> res, uint skipCount, uint takeCount)
{
if (takeCount == 0)
{
return;
}
long tarPos = HeaderSize;
tarPos += m_ItemSize * skipCount;
if (!CanReadNext(tarPos))
{
return;
}
int buffSize = (int)(m_ItemSize * Math.Min(PatchReadMinCount, takeCount));
byte[] buffArr = new byte[buffSize];
var fs = m_BinaryReader.BaseStream;
fs.Position = tarPos;
while (true)
{
if (res.Count >= takeCount)
{
break;
}
if (!CanReadNext(fs.Position))
{
break;
}
var readLen = m_BinaryReader.Read(buffArr, 0, buffSize);
if (readLen == 0)
{
break;
}
var items = ByteHelper.BytesToStruct<T>(buffArr, 0, readLen);
foreach (var item in items)
{
res.Add(item);
if (res.Count >= takeCount)
{
break;
}
}
}
}
/// <summary>
/// 从当前位置开始读取
/// </summary>
/// <returns></returns>
public virtual T? ReadItem()
{
if (CanReadNext(m_BinaryReader.BaseStream.Position))
{
T item;
if (ByteHelper.ReadStruct(m_BinaryReader, out item))
{
return item;
}
}
return null;
}
/// <summary>
/// 从指定位置开始读取
/// </summary>
/// <param name="offset"></param>
/// <returns></returns>
public virtual T? ReadItem(long offset)
{
if (CanReadNext(offset))
{
m_BinaryReader.BaseStream.Position = offset;
T item;
if (ByteHelper.ReadStruct(m_BinaryReader, out item))
{
return item;
}
}
return null;
}
protected bool CanReadNext(long offset)
{
return offset + m_ItemSize <= m_BinaryReader.BaseStream.Length;
}
protected virtual BinaryItemDetail<T> ReadFirst()
{
long tarPos = HeaderSize;
var res = ReadItem(tarPos);
if (res != null)
{
return new BinaryItemDetail<T> { Offset = tarPos, Content = res.Value };
}
return null;
}
protected virtual BinaryItemDetail<T> ReadLast(ref uint acutalTotal)
{
var index = GetTotalPoint();
if (index <= 0)
{
return null;
}
T? res = null;
long tarPos = 0;
while (true)
{
index--;
if (index < 0)
{
break;
}
tarPos = HeaderSize + index * m_ItemSize;
if (tarPos < 0)
{
break;
}
res = ReadItem(tarPos);
if (res != null)
{
break;
}
}
if (index >= 0)
{
acutalTotal = index + 1;
}
if (res != null)
{
return new BinaryItemDetail<T> { Offset = tarPos, Content = res.Value };
}
return null;
}
protected int GetIndex(BinaryItemDetail<T> item)
{
if (item != null)
{
var res = (item.Offset - HeaderSize) / m_ItemSize;
return (int)res;
}
return -1;
}
protected virtual void ResetFilePostion()
{
if (m_BinaryReader != null)
{
m_BinaryReader.BaseStream.Position = 0;
}
}
public void Dispose()
{
m_BinaryReader?.Close();
}
}
public class BinaryItemDetail<T> where T : struct
{
public long Offset { set; get; }
public T Content { set; get; }
}
写入类
public class BaseBinaryFileWriter<T> : IDisposable where T : struct
{
protected readonly string m_TargetFile;
protected BinaryWriter m_MVIdxBinaryWriter;
protected Random rdm = new Random();
public BaseBinaryFileWriter(string file)
{
if (string.IsNullOrEmpty(file))
{
throw new ArgumentNullException();
}
m_TargetFile = file;
if (File.Exists(file))
{
File.Delete(file);
}
var fileInfo = new FileInfo(file);
Directory.CreateDirectory(fileInfo.DirectoryName);
var m_SyncIdxFileStream = new FileStream(m_TargetFile, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.ReadWrite);
m_MVIdxBinaryWriter = new BinaryWriter(m_SyncIdxFileStream);
WriteContent(WriterHeader);
}
protected virtual void WriterHeader()
{
}
protected void WriteContent(Action act, bool needRefreshToDisk = true)
{
if (needRefreshToDisk)
{
var fs = (m_MVIdxBinaryWriter.BaseStream as FileStream);
act?.Invoke();
fs.Flush(true);
}
else
{
act?.Invoke();
}
}
public virtual void AppendItems(List<T> dtItems)
{
WriteContent(() =>
{
dtItems?.ForEach(f =>
{
m_MVIdxBinaryWriter.Write(ByteHelper.StructToBytes(f));
});
});
}
public virtual void AppendItem(T f)
{
AppendItems(new List<T> { f });
}
public virtual void Close()
{
m_MVIdxBinaryWriter?.Close();
}
public void Dispose()
{
Close();
}
}