.NET:如何将结构写入文件流?

时间:2014-07-04 08:10:51

标签: .net struct f# stream binary-data

以下是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

提前致谢!

0 个答案:

没有答案