我正在寻找最有效/直接的方式来做这个简单的C/C++操作:
void ReadData(FILE *f, uint16 *buf, int startsamp, int nsamps)
{
fseek(f, startsamp*sizeof(uint16), SEEK_SET);
fread(buf, sizeof(uint16), nsamps, f);
}
Run Code Online (Sandbox Code Playgroud)
在C#/.NET中.(为了清晰起见,我忽略了返回值 - 生产代码会检查它们.)具体来说,我需要读取许多(可能是10到100的数百万)2字节(16位)"ushort"整数数据样本(固定格式) ,不需要解析)以二进制形式存储在磁盘文件中.关于C方式的好处是它将样本直接读入"uint16*"缓冲区,没有CPU参与,也没有复制.是的,它可能是"不安全的",因为它使用void*指针指向未知大小的缓冲区,但似乎应该有一个"安全"的.NET替代品.
在C#中实现这一目标的最佳方法是什么?我环顾四周,发现了一些提示(使用FieldOffset的"工会",使用指针编组的"不安全"代码,编组),但似乎没有一个适用于这种情况,没有使用某种复制/转换.我想避免使用BinaryReader.ReadUInt16(),因为这非常慢并且CPU密集.在我的机器上,带有ReadUInt16()的for()循环与使用单个Read()直接读入byte []数组之间的速度差异约为25倍.使用非阻塞I/O(在等待磁盘I/O时重叠"有用"处理),该比率可能更高.
理想情况下,我想简单地"伪装"一个ushort []数组作为byte []数组,这样我就可以用Read()直接填充它,或者以某种方式让Read()直接填充ushort []数组:
// DOES NOT WORK!!
public void GetData(FileStream f, ushort [] buf, int startsamp, int nsamps)
{
f.Position = startsamp*sizeof(ushort);
f.Read(buf, 0, nsamps);
}
Run Code Online (Sandbox Code Playgroud)
但是没有Read()方法接受一个ushort []数组,只有一个byte []数组.
这可以直接在C#中完成,还是需要使用非托管代码或第三方库,还是必须采用CPU密集型逐个样本转换?虽然"安全"是首选,但我可以使用"不安全"的代码,或者使用Marshal的一些技巧,我还没想到它.
谢谢你的指导!
[UPDATE]
我想按照dtb的建议添加一些代码,因为似乎有很少的ReadArray实例.这是一个非常简单的,没有显示错误检查.
public void ReadMap(string fname, short [] data, int startsamp, int nsamps)
{
var mmf = MemoryMappedFile.CreateFromFile(fname);
var mmacc = mmf.CreateViewAccessor();
mmacc.ReadArray(startsamp*sizeof(short), …Run Code Online (Sandbox Code Playgroud)