读取内存映射文件或内存映射视图访问器的所有内容,而不知道它的大小

Saw*_*wan 8 .net c# ipc accessor memory-mapped-files

我需要类似于ReadToEnd或ReadAllBytes的东西来使用MappedViewAccessor读取MemoryMappedFile的所有内容,如果我不知道它的大小,我该怎么办呢?

我已经搜索过了,我已经看到了这个问题,但这不是我要找的东西:

如何从.NET中的内存映射文件中快速读取字节?

编辑:

有一个问题,(int)stream.Length没有给我正确的长度,而是给出了内部缓冲区的大小!我需要刷新这个问题,因为它非常紧迫.

Ame*_*wan 15

而是使用Stream:

public static Byte[] ReadMMFAllBytes(string fileName)
{
    using (var mmf = MemoryMappedFile.OpenExisting(fileName))
    {
        using (var stream = mmf.CreateViewStream())
        {
            using (BinaryReader binReader = new BinaryReader(stream))
            {
                return binReader.ReadBytes((int)stream.Length);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 阿梅尔是我的弟弟,他19岁,他总是救助者!谢谢阿梅尔;) (3认同)

Guf*_*ffa 6

你不能这样做.

使用系统页面的最小大小创建视图访问器,这意味着它可能大于实际文件.视图流只是访问者的流形式,因此它也会提供相同的行为.

"视图以系统页面为单位提供,视图大小向上舍入到下一个系统页面大小"

http://msdn.microsoft.com/en-us/library/dd267577.aspx

访问者很乐意在实际文件之外读写,而不会抛出异常.读取时,文件外的任何字节都将为零.写入时,写入文件外部的字节将被忽略.

要从具有原始文件大小的内存映射文件中读取文件,您必须已经知道该大小.


BTJ*_*BTJ 6

这很难回答,因为您的应用程序仍然有许多未指定的细节,但我认为Guffa和Amer的答案仍然部分正确:

  • MemoryMappedFile比文件更多内存; 它是内存中4Kb页面的序列.因此,stream.Length实际上会为您提供所有字节(没有"内部缓冲区大小"),但它可能会提供比您预期更多的字节,因为大小将始终向上舍入到4Kb边界.
  • "文件"语义来自将MemoryMappedFile与真实文件系统文件相关联.假设创建文件的进程总是调整文件大小,那么您可以通过fileSystem获取文件的精确大小.

如果以上所有内容都适合您的应用程序,那么以下内容应该有效:

    static byte[] ReadMemoryMappedFile(string fileName)
    {
        long length = new FileInfo(fileName).Length;
        using (var stream = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite))
        {
            using (var mmf = MemoryMappedFile.CreateFromFile(stream, null, length, MemoryMappedFileAccess.Read, null, HandleInheritability.Inheritable, false))
            {
                using (var viewStream = mmf.CreateViewStream(0, length, MemoryMappedFileAccess.Read))
                {
                    using (BinaryReader binReader = new BinaryReader(viewStream))
                    {
                        var result = binReader.ReadBytes((int)length);
                        return result;
                    }
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

要编写数据,您可以使用:

    private static void WriteData(string fileName, byte[] data)
    {
        using (var stream = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
        {
            using (var mmf = MemoryMappedFile.CreateFromFile(stream, null, data.Length, MemoryMappedFileAccess.ReadWrite, null, HandleInheritability.Inheritable, true))
            {
                using (var view = mmf.CreateViewAccessor())
                {
                    view.WriteArray(0, data, 0, data.Length);
                }
            }

            stream.SetLength(data.Length);  // Make sure the file is the correct length, in case the data got smaller.
        }
    }
Run Code Online (Sandbox Code Playgroud)

但是,当您执行上述所有操作时,您可以直接使用该文件并避免内存映射.如果将其映射到文件系统是不可接受的,那么Guffa在数据本身中编码长度(或结束标记)的答案可能是最好的.