c# - 从文件中高效读取结构化二进制数据
问题描述
我有以下代码片段可以读取二进制文件并对其进行验证:
FileStream f = File.OpenRead("File.bin");
MemoryStream memStream = new MemoryStream();
memStream.SetLength(f.Length);
f.Read(memStream.GetBuffer(), 0, (int)f.Length);
f.Seek(0, SeekOrigin.Begin);
var r = new BinaryReader(f);
Single prevVal=0;
do
{
r.ReadUInt32();
var val = r.ReadSingle();
if (prevVal!=0) {
var diff = Math.Abs(val - prevVal) / prevVal;
if (diff > 0.25)
Console.WriteLine("Bad!");
}
prevVal = val;
}
while (f.Position < f.Length);
不幸的是,它工作得非常缓慢,我正在寻求改进。在 C++ 中,我只需将文件读入字节数组,然后将该数组重铸为结构数组:
struct S{
int a;
float b;
}
我将如何在 C# 中执行此操作?
解决方案
使用与您的 C++ 代码完全相同的显式布局 ( )定义 a struct
(可能是 a ),然后是:readonly struct
[StructLayout(LayoutKind.Explicit)]
- 将文件作为内存映射文件打开,获取指向数据的指针;
unsafe
在原始指针上使用代码,或Unsafe.AsRef<YourStruct>
在数据上使用,并Unsafe.Add<>
进行迭代 - 将文件作为内存映射文件打开,获取指向数据的指针;在(您的)指针上创建自定义内存
T
,并在跨度上进行迭代 - 将文件打开为
byte[]
;Span<byte>
在 上创建 abyte[]
,然后用于MemoryMarshal.Cast<,>
创建 aSpan<YourType>
,并对其进行迭代 - 将文件打开为
byte[]
; 用于fixed
固定byte*
并获取指针;使用unsafe
代码走指针 - 一些涉及“管道”的东西 - a
Pipe
是缓冲区,可能StreamConnection
用于FileStream
填充管道,以及从管道中出列的工作循环;复杂性:缓冲区可能不连续,并且可能在不方便的地方拆分;可解,但只要第一个跨度不是至少 8 个字节,就需要微妙的代码
(或这些概念的某种组合)
其中任何一个都应该像您的 C++ 版本一样工作。第四种很简单,但是对于非常大的数据,您可能希望更喜欢内存映射文件
推荐阅读
- c# - C#.NET 4.6 中的条带充电
- matlab - NetCDF 库在执行“创建”函数期间遇到错误 - “无效参数 (22)”
- list - 扑。按列表字段分组列表
- android - W / System.err:java.net.SocketException:套接字失败:Android中的EACCES(权限被拒绝)
- amazon-web-services - 对于现有的 AWS ACM 证书,我可以从电子邮件验证切换到 DNS 验证吗?
- openshift - replicas=1 - 这意味着 1 个 pod 还是 1 个 pod + 1 个副本正在运行?
- azure - Azure 测试和反馈 - 可以查看以前的会话吗?
- c++ - 为什么要像 MPFR 那样定义“typedef someStruct someName[1]”?
- android-studio - 无法在 Windows 10 上打开 Android Studio 4 - 白屏而不是项目
- jquery - 正则表达式使 HTML 输入数字仅包括负值