-->

阅读映射视图访问内存映射文件或内存中的所有内容,而不知道它的大小(Read all contents

2019-07-20 03:35发布

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

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

我怎样才能快速阅读:在.NET内存映射文件的字节?

编辑:

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

Answer 1:

而是使用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);
            }
        }
    }
}


Answer 2:

你不能做到这一点。

甲视图访问与系统页的最小尺寸,这意味着它可以比实际的文件大创建。 视图流只是一个访问流形式,所以它也将给予相同的行为。

“在系统页面的单位提供的视图,视图的大小舍入到下一个系统页面大小”

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

访问者会很高兴地阅读和实际的文件之外写未抛出异常。 读取时,该文件之外的任何字节都只是零。 书写时,文件外写入字节只是忽略。

要读取从原始文件的确切大小内存映射文件的文件,你必须已经知道大小。



Answer 3:

这是很难回答的,因为还有你没有指定你的应用程序中的许多细节,但我认为这两个Guffa的和阿米尔的答案仍然是部分正确的:

  • 甲MemoryMappedFile比文件的更多存储器; 它是在内存中4KB页的序列。 所以,stream.Length将在事实上给你所有的字节(不存在“内部缓存大小”),但比预期的,因为大小总是会四舍五入为4KB的边界它可能给你更多的字节。
  • “文件”语义来自MemoryMappedFile关联到一个真正的文件系统文件。 假设它创建该文件的过程中始终调整文件的大小,那么你可以通过文件系统中获取文件的尺寸精确。

如果以上所有会适合你的应用程序,那么下面应该工作:

    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;
                    }
                }
            }
        }
    }

要写入数据,您可以使用此:

    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.
        }
    }

但是,你的时间做上述所有你可能做的一样好,直接使用的文件,避免内存映射。 如果将它映射到文件系统是不能接受的,则在数据本身编码长度(或结束标记)的Guffa的回答可能是最好的。



Answer 4:

使用FileInfo类获得的长度,如下图所示

using System.Data;
using System.IO;
using System.IO.Compression;
using System.IO.MemoryMappedFiles;

// ...

public void WriteToMemoryMap(DataSet ds, string key, string fileName)
{
    var bytes = CompressData(ds);
    using (MemoryMappedFile objMf = MemoryMappedFile.CreateFromFile(fileName, FileMode.OpenOrCreate, key, bytes.Length))
    {
        using (MemoryMappedViewAccessor accessor = objMf.CreateViewAccessor())
        {
            accessor.WriteArray(0, bytes, 0, bytes.Length);
        }
    }
}
public DataSet ReadFromMemoryMap(string fileName)
{
    var fi = new FileInfo(fileName);
    var length = (int)fi.Length;
    var newBytes = new byte[length];
    using (MemoryMappedFile objMf = MemoryMappedFile.CreateFromFile(fileName, FileMode.Open))
    {
        using (MemoryMappedViewAccessor accessor = objMf.CreateViewAccessor())
        {
            accessor.ReadArray(0, newBytes, 0, length);
        }
    }
    return DecompressData(newBytes);
}
public byte[] CompressData(DataSet ds)
{
    try
    {
        byte[] data = null;
        var memStream = new MemoryStream();
        var zipStream = new GZipStream(memStream, CompressionMode.Compress);
        ds.WriteXml(zipStream, XmlWriteMode.WriteSchema);
        zipStream.Close();
        data = memStream.ToArray();
        memStream.Close();
        return data;
    }
    catch (Exception)
    {
        return null;
    }
}
public DataSet DecompressData(byte[] data)
{
    try
    {
        var memStream = new MemoryStream(data);
        var unzipStream = new GZipStream(memStream, CompressionMode.Decompress);
        var objDataSet = new DataSet();
        objDataSet.ReadXml(unzipStream, XmlReadMode.ReadSchema);
        unzipStream.Close();
        memStream.Close();
        return objDataSet;
    }
    catch (Exception)
    {
        return null;
    }
}


Answer 5:

就在@Amer空沙旺的解决方案转换为Vb.NET:

' Usage Example:
' Dim ReadBytes As Byte() = ReadMemoryMappedFile(Name:="My MemoryMappedFile Name") ' Read the byte-sequence from memory.
' Dim Message As String = System.Text.Encoding.ASCII.GetString(ReadBytes.ToArray) ' Convert the bytes to String.
' Message = Message.Trim({ControlChars.NullChar}) ' Remove null chars (leading zero-bytes)
' MessageBox.Show(Message, "", MessageBoxButtons.OK) ' Show the message.    '
'
''' <summary>
''' Reads a byte-sequence from a <see cref="IO.MemoryMappedFiles.MemoryMappedFile"/> without knowing the exact size.
''' Note that the returned byte-length is rounded up to 4kb, 
''' this means if the mapped memory-file was written with 1 byte-length, this method will return 4096 byte-length. 
''' </summary>
''' <param name="Name">Indicates an existing <see cref="IO.MemoryMappedFiles.MemoryMappedFile"/> assigned name.</param>
''' <returns>System.Byte().</returns>
Private Function ReadMemoryMappedFile(ByVal Name As String) As Byte()

    Try
        Using MemoryFile As IO.MemoryMappedFiles.MemoryMappedFile =
            IO.MemoryMappedFiles.MemoryMappedFile.OpenExisting(Name, IO.MemoryMappedFiles.MemoryMappedFileRights.ReadWrite)

            Using Stream = MemoryFile.CreateViewStream()

                Using Reader As New BinaryReader(Stream)

                    Return Reader.ReadBytes(CInt(Stream.Length))

                End Using ' Reader

            End Using ' Stream

        End Using ' MemoryFile

    Catch exNoFile As IO.FileNotFoundException
        Throw
        Return Nothing

    Catch ex As Exception
        Throw

    End Try

End Function


Answer 6:

我想有从MemoryStream的.ToArray东西()方法返回的所有字节,并在下面工作的代码对我来说:

using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting(MemoryMappedName))
{
    using (MemoryMappedViewStream stream = mmf.CreateViewStream())
    {
        using (MemoryStream memStream = new MemoryStream())
        {
            stream.CopyTo(memStream);
            return memStream.ToArray();
        }
    }
}

干杯!



文章来源: Read all contents of memory mapped file or Memory Mapped View Accessor without knowing the size of it