以下是F#
中struct MyHeader
的定义
open System.Runtime.InteropServices;
[<Struct; StructLayout(LayoutKind.Sequential)>]
type MyHeader =
val mutable Timestamp : uint32
val mutable Size : uint16
应该等同于下面的C struct
struct __attribute__((packed)) MyHeader {
uint32_t Timestamp;
uint16_t Size;
};
有一个非常方便的助手班MemoryMappedViewAccessor
,可以作为一个&#34;视图&#34; MemoryMappedFile
并且其通用方法Read(T)
负责处理有关将数据读入结构的每个成员的所有内容,前提是我指定了正确的&#34;偏移量&#34;在内存映射文件中。虽然我真正想要的是类似流的操作,而不是随机访问,
std::ifstream ifs("infile.dat", std::ios::binary);
MyHeader hdr;
while (ifs.read(reinterpret_cast<char *>(&hdr), sizeof hdr)) {
char payload[hdr.Size];
ifs.read(payload, hdr.Size);
...
}
我可以通过简单的循环轻松模拟它们;
use mmf = System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile("infile.dat", System.IO.FileMode.Open)
use view = mmf.CreateViewAccessor()
let loop offset =
if offset < view.Capacity then
let hdr = MyHeader()
view.Read(offset, &hdr)
let payload = Array.create hdr.Size 0y
view.ReadArray(offset + sizeof<MyHeader>, payload, 0, hdr.Size)
...
loop <| offset + sizeof<MyHeader> + hdr.Size
else
()
loop 0L
然而,我不能将我的结构写入二进制流。 Write(T)
MemoryMappedViewAccessor
方法对我来说并不是很有用,因为它假设我已经拥有足够大的后端文件;换句话说,它不是用于按块扩展输出文件块。如何在F#/ .NET中实现类似下面的内容?
std::ifstream ifs("infile.dat", std::ios::binary);
std::ofstream ofs("outfile.dat", std::ios::binary);
MyHeader hdr;
while (ifs.read(reinterpret_cast<char *>(&hdr), sizeof hdr)) {
char payload[hdr.Size];
ifs.read(payload, hdr.Size);
... // modify hdr and payload
ofs.write(reinterpret_cast<const char *>(&hdr), sizeof hdr);
ofs.write(payload, hdr.Size);
}
如果我不需要像MemoryStream
这样的大型内存缓冲区,那就太好了。但是我的数据文件小于1GB,所以我可以将整个文件读入内存。此外,如果有更好的方法,我不必使用mmap。
注意:我在Ubuntu 12.04上使用F#3.0 / Mono 2.10
提前致谢!