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);
}
}
}