c# 中结构体 的定义字符串字段(性能优化)

在结构体中尽量定义值类型,可以通过指针快速读取,比如一下示例:

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);
相关推荐
房开民2 小时前
可变参数模板
java·开发语言·算法
t***5442 小时前
如何在现代C++中更有效地应用这些模式
java·开发语言·c++
唐青枫3 小时前
C#.NET ObjectPool 深入解析:对象复用、池化策略与使用边界
c#·.net
Victoria.a4 小时前
python基础语法
开发语言·python
xiaoyaohou114 小时前
023、数据增强改进(二):自适应数据增强与AutoAugment策略
开发语言·python
鬼圣4 小时前
Python 上下文管理器
开发语言·python
星空椰5 小时前
JavaScript 基础进阶:分支、循环与数组实战总结
开发语言·javascript·ecmascript
yong99905 小时前
IHAOAVOA:天鹰优化算法与非洲秃鹫优化算法的混合算法(Matlab实现)
开发语言·算法·matlab
t***5445 小时前
有哪些常见的架构设计模式在现代C++中应用
开发语言·c++