C# 如何提高将大型二进制文件读入结构的性能?

C# 如何提高将大型二进制文件读入结构的性能?,c#,struct,binaryfiles,C#,Struct,Binaryfiles,我将一些大型二进制文件读入结构中,然后将这些结构添加到列表中,以便在以后循环使用它们。一切正常,只是读取结构的速度比预期的慢。以下是相关代码: //128 bytes total [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] public struct RAMPrec2 { public double now; // Days in double precis

我将一些大型二进制文件读入结构中,然后将这些结构添加到列表中,以便在以后循环使用它们。一切正常,只是读取结构的速度比预期的慢。以下是相关代码:

//128 bytes total
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct RAMPrec2
{
    public double now;                 // Days in double precision (see note 1)
    public int VehLatitude;            // Milliarcseconds (see note 2)
    public int VehLongitude;           // Milliarcseconds (see note 2)
    public short VehLatUncertainty;    // Meters as 16-bit int
    public short VehLonUncertainty;    // Meters as 16-bit int
    public short Reserved1;      // Meters as 16-bit int (see note 3)
    public short Reserved2;      // Meters as 16-bit int
    public float VehAltitude;          // Meters as a float
    public float VehFirstRet;          // Meters as a float
    public float VehDepth;             // Meters as a float
    public float VehSpeed;             // Knots as a float
    public float VehHeading;           // degrees as a float (e.g. 0.0 - 359.9999)
    public float VehCourse;            // degrees as a float (e.g. 0.0 - 359.9999)
    public float VehRoll;              // degrees as a float (positive is counterclockwise roll)
    public float VehPitch;             // degrees as a float (negative is downward pitch)
    public float VehVOS;               // Meters/sec
    public int DisplayNorthing;        // Centimeters as 32-bit integer
    public int DisplayingEasting;      // Centimeters as 32-bit integer
    public int OriginalLatitude;       // Milliarcseconds as 32-bit integer
    public int OriginalLongitude;      // Milliarcseconds as 32-bit integer
    public int DeltaNorthing;          // Centimeters as 32-bit integer
    public int DeltaEasting;           // Centimeters as 32-bit integer
    public short FixFlags;             // 16 bit flags. (note 5)
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] // 8 sets of 32-bit values,sensor specific (note 3)
    public int[] SData;
    public ushort DataAvailFlags;      // 16 bit mask field (note 4)
    public ushort QA_Flag;             // 16 bit mask field (note 6)
    public short EventFlag;            // 2-byte reserved field
    public float Reserved3;            // 4-byte reserved field
}

public Boolean ReadRampFileType2(List<string> rampPaths) //rampPaths is just a list of filepaths for each binary file to be read
{
    for (int i = 0; i < rampPaths.Count; i++)
    {
        try
        {
            using (var stream = new FileStream(rampPaths[i], FileMode.Open, FileAccess.Read, FileShare.None)) //open up a stream on the specified file
            {
                stream.Position = 8192; //skip header

                while (stream.Position < (stream.Length)) //while not at end of file
                {
                    RAMPrec2 ramp = ReadRecFromStream<RAMPrec2>(stream, Marshal.SizeOf(typeof(RAMPrec2))); //read in each record to the ramp struct
                    AddRecDataToListsType2(ramp, vehicles[i]);
                }
            }
        }
        catch (Exception e) //something went wrong
        {
            return false;
        }
    }
    return true;
}

private T ReadRecFromStream<T>(Stream stream, int size) where T : struct
{
    byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
    stream.Read(buffer, 0, size);
    GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    try
    {
        return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    }
    finally
    {
        handle.Free();
    }
}

//I have a vehicle class with a bunch of lists. This adds the data from the structs I read in to these lists
public void AddRecDataToListsType2(RAMPrec2 ramp, VehicleModel vehicle)
{
    vehicle.NowTime.Add(ramp.now);
    vehicle.VehLat.Add(ramp.VehLatitude / MILLIARCTODEG);
    vehicle.VehLong.Add(ramp.VehLongitude / MILLIARCTODEG);
    vehicle.VehHead.Add(ramp.VehHeading);
    vehicle.VehSpeed.Add(ramp.VehSpeed);
    vehicle.VehTWD.Add(ramp.VehAltitude + ramp.VehDepth);
    vehicle.VehAlt.Add(ramp.VehAltitude);
    vehicle.VehDep.Add(ramp.VehDepth);
    vehicle.VehRoll.Add(ramp.VehRoll);
    vehicle.VehPit.Add(ramp.VehPitch);
}
//总共128字节
[StructLayout(LayoutKind.Sequential,Pack=1,CharSet=CharSet.Ansi)]
公共结构RAMPrec2
{
public double now;//双精度天数(见注1)
public int VehLatitude;//毫秒(见注2)
public int vehlongity;//毫弧秒(见注2)
公共短维拉特不确定性;//米为16位整数
公共短车辆不确定性;//米为16位整数
公共短预留1;//表为16位整数(见注3)
公共短预留2;//米为16位整数
公共浮标VehAltitude;//浮标为米
公共浮标VehFirstRet;//浮标为米
公共浮点数VehDepth;//浮点数为米
公共浮点数VehSpeed;//浮点数
公共浮动车头;//作为浮动的度数(例如0.0-359.9999)
公共浮动VehCourse;//作为浮动的度数(例如0.0-359.9999)
public float VehRoll;//浮点数为度(正为逆时针滚动)
public float VehPitch;//浮点数为度(负为向下倾斜)
公共浮标VehVOS;//米/秒
public int显示北距;//厘米为32位整数
public int DisplayingEasting;//厘米为32位整数
public int OriginalLatitude;//毫秒为32位整数
public int OriginalLongitude;//毫秒为32位整数
public int DeltaNorthing;//厘米为32位整数
public int DeltaEasting;//厘米为32位整数
public short FixFlags;//16位标志。(注5)
[Marshallas(UnmanagedType.ByValArray,SizeConst=8)]//8组32位值,特定于传感器(注3)
公共国际[]SData;
public-ushort-DataAvailFlags;//16位掩码字段(注4)
公共ushort QA_标志;//16位掩码字段(注6)
public short EventFlag;//2字节保留字段
public float Reserved3;//4字节保留字段
}
public Boolean ReadRampFileType2(列出rampPaths)//rampPaths只是要读取的每个二进制文件的文件路径列表
{
对于(int i=0;i

我循环浏览我拥有的二进制文件列表,并在每个文件上打开一个文件流,跳到二进制文件中第一个“struct”出现的位置,然后将其读入一个struct,然后将其字段添加到一组列表中,然后重复,直到文件结束。这是缓慢的,我觉得必须有一个更好的方式做事情

这是内存映射的理想候选者

不必在内存中读取结构,您可以在数据文件上创建映射视图,并像在内存中一样访问结构

< >我在C++中没有使用内存映射,在不安全的模式下,你可以直接在映射的视图上使用<代码> RAMPREC2*/COD>,并使用该指针循环记录/结构,就像C++一样。有关示例,请参见


您甚至可以取消创建单独的列表,因为所有字段都可以通过映射视图直接访问。

试试这个…

// this would be how to call...

foreach (var item in ReadFile<RAMPrec2>("testFile.bin", 0).Select((v, i) => new { Value = v, Index = i }))
{
    var vehicle = vehicles[item.Index];
    var ramp = item.Value;
    vehicle.NowTime.Add(ramp.now);
    vehicle.VehLat.Add(ramp.VehLatitude / MILLIARCTODEG);
    vehicle.VehLong.Add(ramp.VehLongitude / MILLIARCTODEG);
    vehicle.VehHead.Add(ramp.VehHeading);
    vehicle.VehSpeed.Add(ramp.VehSpeed);
    vehicle.VehTWD.Add(ramp.VehAltitude + ramp.VehDepth);
    vehicle.VehAlt.Add(ramp.VehAltitude);
    vehicle.VehDep.Add(ramp.VehDepth);
    vehicle.VehRoll.Add(ramp.VehRoll);
    vehicle.VehPit.Add(ramp.VehPitch);
}
//这就是如何调用。。。
foreach(ReadFile中的var项(“testFile.bin”,0)。选择((v,i)=>new{Value=v,Index=i}))
{
var车辆=车辆[项目索引];
var ramp=项目价值;
vehicle.NowTime.Add(ramp.now);
车辆高度增加(坡道高度/毫弧度);
车辆长度增加(坡道长度/毫弧度);
vehicle.VehHead.Add(坡道.VehHeading);
vehicle.VehSpeed.Add(坡道.VehSpeed);
vehicle.VehTWD.Add(ramp.VehAltitude+ramp.VehDepth);
vehicle.VehAlt.Add(坡道.VehAltitude);
vehicle.VehDep.Add(坡道.VehDepth);
vehicle.VehRoll.Add(坡道.VehRoll);
车辆
static IEnumerable<T> ReadFile<T>(string fileName, int offset) where T : struct
{
    using (var reader = File.OpenRead(fileName))
    {
        var sizeOf = Marshal.SizeOf(typeof(T));
        var ptr = Marshal.AllocHGlobal(sizeOf);
        try
        {
            reader.Position = offset;
            var fileLength = reader.Length + reader.Position;
            var buffer = new byte[sizeOf];
            for (var p = reader.Position; p < fileLength; p += sizeOf)
            {
                reader.Read(buffer, 0, sizeOf);
                Marshal.Copy(buffer, 0, ptr, sizeOf);
                var ret = Marshal.PtrToStructure(ptr, typeof(T));
                var str = (T)ret;
                yield return str;
            }
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }
    }
}