在结构体中尽量定义值类型,可以通过指针快速读取,比如一下示例:
cs
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct UseDetail
{
public const int useName_Size = 20;
public fixed byte useName[useName_Size];
public string GetUseName()
{
// 必须 fixed!
fixed (byte* p = useName)
{
int len = 0;
while (len < useName_Size && p[len] != 0)
len++;
return Encoding.ASCII.GetString(p, len);
}
}
public void SetUserName(string content)
{
byte[] source = Encoding.ASCII.GetBytes(content);
// 必须 fixed!.NET4.0 强制要求
fixed (byte* pDest = useName)
{
int copyLength = Math.Min(source.Length, useName_Size);
for (int i = 0; i < copyLength; i++)
{
pDest[i] = source[i];
}
}
}
}
快速读写二进制文件
cs
public static unsafe class IdStructHelperK8
{
/// <summary>
/// 写入结构体到文件
/// </summary>
public static void WriteStruct<T>(string filePath, T data) where T : struct
{
int structSize = Marshal.SizeOf(typeof(T));
byte[] buffer = new byte[structSize];
fixed (byte* p = buffer)
{
*(T*)p = data;
}
File.WriteAllBytes(filePath, buffer);
}
/// <summary>
/// 从文件读取结构体
/// </summary>
public static T ReadStruct<T>(string filePath) where T : struct
{
byte[] buffer = File.ReadAllBytes(filePath);
fixed (byte* p = buffer)
{
return *(T*)p;
}
}
public static T ReadStruct<T>(byte[] buffer) where T : struct
{
fixed (byte* p = buffer)
{
return *(T*)p;
}
}
}
工具类,方便以后使用,性能最高
cs
#pragma warning disable CS8500 // 👈 就加这一行
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
/// <summary>
/// 方便修改结构内容
/// </summary>
/// <typeparam name="T"></typeparam>
public unsafe class StructModifyWrapper<T> where T : struct
{
public T* Content { set; get; }
}
/// <summary>
/// 二进制文件操作类, 小于100M的文件最好一次性读入内存后 然后转换
/// </summary>
public static unsafe class StructHelperWithFile
{
/// <summary>
/// 写入结构体到文件
/// </summary>
public static void WriteStruct<T>(string filePath, T data) where T : struct
{
WriteStructs(filePath, new List<T> { data });
}
public static void WriteStructs<T>(string filePath, List<T> data) where T : struct
{
var buffer = StructHelper.WriteStructs(data);
File.WriteAllBytes(filePath, buffer);
}
/// <summary>
/// 从文件读取结构体
/// </summary>
public static T ReadStruct<T>(string filePath) where T : struct
{
var t = ReadStructs<T>(filePath);
if (t.IsEmpty())
{
throw new Exception();
}
return t[0];
}
public static T[] ReadStructs<T>(string filePath) where T : struct
{
byte[] buffer = File.ReadAllBytes(filePath);
return StructHelper.ReadStructs<T>(buffer);
}
}
/// <summary>
/// 基于指针的结构体读写,性能最快
/// </summary>
/// <typeparam name="T"></typeparam>
public unsafe class StructHelper_PTR<T> : IStructHelper<T> where T : struct
{
readonly int m_ItemSize;
public StructHelper_PTR()
{
m_ItemSize = Marshal.SizeOf(typeof(T));
}
public byte[] Save(List<T> items)
{
// 空列表直接返回空数组
if (items == null || items.Count == 0)
return new byte[0];
// .NET4.0 标准获取结构体大小(安全、稳定)
int structSize = Marshal.SizeOf(typeof(T));
int count = items.Count;
int totalSize = structSize * count;
// 分配最终字节数组(一次分配,高性能)
byte[] buffer = new byte[totalSize];
// 固定内存,防止GC移动
fixed (byte* pBuffer = buffer)
{
for (int i = 0; i < count; i++)
{
// 计算目标位置指针
T* pDest = (T*)(pBuffer + i * structSize);
// 直接赋值:极致性能(.NET 4.0 完美支持)
*pDest = items[i];
}
}
return buffer;
} // 并行阈值:超过这个数量才启用多线程(根据性能实测得出)
private const int _parallelThreshold = 2000;
/// <summary>
/// 从字节数组读取【多个结构体】自动计算数量并返回 List<T>
/// </summary>
public T[] Read(byte[] buffer)
{
if (buffer == null || buffer.Length == 0)
return null;
int count = buffer.Length / m_ItemSize;
if (count == 0)
return null;
T[] array = new T[count];
// 方案:先把首地址转成 IntPtr,就可以跨线程使用了!
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
IntPtr pBuffer = handle.AddrOfPinnedObject();
if (count > _parallelThreshold)
{
// 并行多线程读取(安全!无CS1764!)
Parallel.For(0, count, i =>
{
IntPtr p = IntPtr.Add(pBuffer, i * m_ItemSize);
//array[i] = (T)Marshal.PtrToStructure(p, typeof(T));
array[i] = *(T*)(p);
});
}
else
{
// 单线程指针版本(最快)
unsafe
{
byte* p = (byte*)pBuffer;
for (int i = 0; i < count; i++)
{
array[i] = *(T*)(p + i * m_ItemSize);
}
}
}
}
finally
{
handle.Free(); // 必须释放!
}
return array;
}
public byte[] Update(byte[] structBuffer, Action<StructModifyWrapper<T>> doUpdate)
{
var structBuffer_New = new byte[structBuffer.Length];
{
fixed (byte* p = structBuffer)
{
var k3 = *(T*)p;
var v3 = new StructModifyWrapper<T>() { Content = &k3 };
doUpdate.Invoke(v3);
fixed (byte* p22 = structBuffer_New)
{
*(T*)p22 = k3;
}
}
}
return structBuffer_New;
}
public void Dispose()
{
}
}
/// <summary>
/// 基于托管内存的结构体读写, 性能较慢
/// </summary>
/// <typeparam name="T"></typeparam>
public class StructHelper_Marshal<T> : IStructHelper<T> where T : struct
{
readonly int m_ItemSize;
readonly Type m_typeFromHandle;
readonly IntPtr m_HDPTR;
public StructHelper_Marshal()
{
Type typeFromHandle = typeof(T);
m_typeFromHandle = typeFromHandle;
m_ItemSize = Marshal.SizeOf(typeFromHandle);
m_HDPTR = Marshal.AllocHGlobal(m_ItemSize);
}
public byte[] Save(List<T> data)
{
if (data.IsEmpty())
{
return null;
}
byte[] databytes = new byte[m_ItemSize];
MemoryStream ms = new MemoryStream();
try
{
data.ForEach(delegate (T f)
{
Marshal.StructureToPtr((object)f, m_HDPTR, fDeleteOld: false);
Marshal.Copy(m_HDPTR, databytes, 0, m_ItemSize);
ms.Write(databytes, 0, databytes.Length);
});
return ms.ToArray();
}
finally
{
if (ms != null)
{
((IDisposable)ms).Dispose();
}
}
}
public T[] Read(byte[] bytes)
{
if (bytes.IsEmpty())
{
return null;
}
var num = m_ItemSize;
var endIndex = bytes.Length;
var startIndex = 0;
var total = endIndex / num;
if (total == 0)
{
return null;
}
var list = new T[total];
int i = 0;
while (startIndex + num <= endIndex)
{
Marshal.Copy(bytes, startIndex, m_HDPTR, num);
list[i] = ((T)Marshal.PtrToStructure(m_HDPTR, m_typeFromHandle));
startIndex += num;
i++;
}
return list;
}
public byte[] Update(byte[] structBuffer, Action<StructModifyWrapper<T>> doUpdate)
{
throw new Exception();
}
public void Dispose()
{
Marshal.FreeHGlobal(m_HDPTR);
}
}
/// <summary>
/// 结构体转换类
/// </summary>
public static unsafe class StructHelper
{
public static T[] ReadStructs<T>(byte[] buffer) where T : struct
{
using (IStructHelper<T> eng = GetHelp<T>())
{
return eng.Read(buffer);
}
}
public static byte[] WriteStructs<T>(List<T> items) where T : struct
{
using (IStructHelper<T> eng = GetHelp<T>())
{
return eng.Save(items);
}
}
public static void Modify<T>(string destSCSCache, Action<StructModifyWrapper<T>> doUpdate) where T : struct
{
using (IStructHelper<T> eng = GetHelp<T>())
{
// 以 读写模式 打开文件
using (FileStream fs = new FileStream(destSCSCache, FileMode.Open, FileAccess.ReadWrite))
{
int HEAD_SIZE = 0;
var STRUCT_SIZE = Marshal.SizeOf(typeof(T));
// --------------------------
// 2. 读取所有结构体(N个)
// --------------------------
long dataStartPos = HEAD_SIZE; // 数据从第100字节开始
long remainLength = fs.Length - dataStartPos;
int structCount = (int)(remainLength / STRUCT_SIZE);
// 循环读取每个结构体
for (int i = 0; i < structCount; i++)
{
// 定位到第 i 个结构体位置
fs.Position = dataStartPos + i * STRUCT_SIZE;
// 读取 100 字节
byte[] structBuffer = new byte[STRUCT_SIZE];
fs.Read(structBuffer, 0, STRUCT_SIZE);
byte[] structBuffer_New = eng.Update(structBuffer, doUpdate);
// 写回文件(覆盖原位置)
fs.Position = dataStartPos + i * STRUCT_SIZE;
fs.Write(structBuffer_New, 0, STRUCT_SIZE);
}
}
}
}
private static IStructHelper<T> GetHelp<T>() where T : struct
{
IStructHelper<T> eng;
bool isValueT = IsAllValueType<T>();
if (isValueT)
{
eng = new StructHelper_PTR<T>();
}
else
{
eng = new StructHelper_Marshal<T>();
}
return eng;
}
/// <summary>
/// 判断结构体【所有字段】都是值类型(不含引用类型)
/// </summary>
public static bool IsAllValueType<T>() where T : struct
{
return IsAllValueType(typeof(T));
}
/// <summary>
/// 递归判断:所有字段都是值类型
/// </summary>
private static bool IsAllValueType(Type type)
{
// 必须是值类型(struct / 基础类型)
if (!type.IsValueType)
return false;
// 枚举 = 合法
if (type.IsEnum)
return true;
// 获取所有实例字段(public / private / 不获取静态)
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (FieldInfo field in fields)
{
Type fieldType = field.FieldType;
var s5 = IsFixedByteBuffer(field);
if (s5)
{
continue;
}
// 普通值类型(int/long/bool/double 等)→ 合法
//if (fieldType.IsValueType)
// continue;
// 指针类型 → 视为值类型(你的 fixed byte 就是指针)
if (fieldType.IsPointer)
continue;
// 字符串 = 引用类型 → 直接不通过
if (fieldType == typeof(string))
return false;
// 递归检查:如果是嵌套结构体,也要检查它内部
if (!IsAllValueType(fieldType))
return false;
}
return true;
}
/// <summary>
/// 判断一个字段是否为 fixed byte[] 不安全缓冲区
/// </summary>
public static bool IsFixedByteBuffer(FieldInfo field)
{
// 1. 必须是 unsafe 修饰的字段(有 FixedBufferAttribute)
var attr = field.GetCustomAttribute<FixedBufferAttribute>();
if (attr == null)
return false;
// 2. 必须是 byte 类型
if (attr.ElementType != typeof(byte))
return false;
return true;
}
public static unsafe string GetString(byte* p, int bufferSize)
{
// 空指针保护
if (p == null || bufferSize <= 0)
return string.Empty;
// 安全计算实际字符串长度(遇到0停止)
int len = 0;
while (len < bufferSize && p[len] != 0)
len++;
// 空字符串直接返回
if (len == 0)
return string.Empty;
// 转字符串(.NET4.0 最安全重载)
return GetENd().GetString(p, len);
}
public static unsafe void SetString(string content, byte* pDest, int bufferSize)
{
// 1. 空指针校验
if (pDest == null || bufferSize <= 0)
return;
// 2. 【必须】清空缓冲区全部填0,防止旧数据残留
for (int i = 0; i < bufferSize; i++)
pDest[i] = 0;
// 3. 空字符串直接返回(已经清0)
if (string.IsNullOrEmpty(content))
return;
// 4. 转字节(你的编码 GetENd())
byte[] bytes = GetENd().GetBytes(content);
// 5. 最多复制 缓冲区大小-1(留位置放结束符\0)
int copyLen = Math.Min(bytes.Length, bufferSize - 1);
// 6. 复制字节
for (int i = 0; i < copyLen; i++)
pDest[i] = bytes[i];
// 7. 【必须】字符串末尾加 \0 结束符(否则读取乱码)
pDest[copyLen] = 0;
}
public static Encoding GetENd()
{
/*
CharSet.Ansi = 1 字节 / 字符(对应 GBK、GB2312、系统本地编码)
CharSet.Unicode = 2 字节 / 字符(UTF-16,C# string 原生)
CharSet.Auto = 由操作系统决定(Windows = Unicode)
CharSet.Ansi 在中文系统里 = GBK
Marshal.PtrToStringAnsi() 底层也是按 GBK 解析
*/
return Encoding.GetEncoding("GBK");
}
}
}
测试代码:
string n2FIle = fmmm;
var p3 = StructHelperWithFile.ReadStructs<SCSStruct_1_CRH6_Samp_PTR>(fmmm);