2013-02-19 56 views
6

我需要类似于ReadToEnd或ReadAllBytes使用MappedViewAccessor读取MemoryMappedFile的所有内容,如果我不知道大小它,我该怎么做?阅读内存映射文件或内存映射视图访问器的所有内容而不知道它的大小

我已经寻找它

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

How can I quickly read bytes from a memory mapped file in .NET?

编辑:

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

+1

我不认为这是一个有效的问题...固件是多么的大小以适应您的数据必须符合指定的内部存储区域区。如果您没有这个大小,那么您需要提供给您或在通过抽象或API使用该文件之前知道的大小。您也可以在内存映射文件中创建一个标头,以指示长度和当前偏移量(如果需要)。例如,如果您的文件大小小于页面大小,并且我在写入大小后写入该区域.. – Jay 2013-03-12 13:31:44

回答

11

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

Amer是我的弟弟,他是19,他始终是救助者!谢谢阿米尔;) – 2013-02-19 10:04:14

+0

答案有一些问题,请提供一个更好的答案。 – 2013-03-11 19:32:58

+0

令人惊讶,我没有发现任何问题读取/写入字符串的方式,那些四舍五入4096字节获取字符串字节时出去。真的很有用的解决方案。 – ElektroStudios 2014-08-21 03:01:10

5

你不能做到这一点。

视图访问器是用系统页面的最小尺寸创建的,这意味着它可能比实际文件大。视图流只是访问者的流形式,所以它也会给出相同的行为。 “在系统页面的单位提供意见,并认为 的大小舍入到下一个系统页面大小”

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

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

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

+0

你对IPC有什么建议?把一些尾巴添加到文件?或者是什么? – 2013-03-05 19:09:09

+0

我在考虑把文件的大小放在开头。 – 2013-03-05 19:10:18

+0

@MohamedSakherSawan:是的,可以使用文件中的数据本身可以用来确定大小的任何文件结构。 – Guffa 2013-03-05 19:39:25

6

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

  • 一个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; 
        } 
       } 
      } 
     } 
    } 

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

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对数据本身的长度(或结束标记)进行编码的答案可能是最好的。

+0

无需获取FileInfo(fileName).Length CreateFromFile internaly使内存映射文件的容量与文件的大小相匹配。只需传递0即可。 – 2016-05-06 21:31:26

0

就在@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 
0

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

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

干杯!

0

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

public void WriteToMemoryMap(DataSet ds, string key, string fileName) 
    { 
     var bytes = CompressData(ds); 
     using (System.IO.MemoryMappedFiles.MemoryMappedFile objMf = System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile(fileName, System.IO.FileMode.OpenOrCreate, key, bytes.Length)) 
     { 
      using (System.IO.MemoryMappedFiles.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 (System.IO.MemoryMappedFiles.MemoryMappedFile objMf = System.IO.MemoryMappedFiles.MemoryMappedFile.CreateFromFile(fileName, FileMode.Open)) 
     { 
      using (System.IO.MemoryMappedFiles.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 ex) 
     { 
      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 ex) 
     { 
      return null; 
     } 
    } 
+0

如果可能的话,请详细解释一下这段代码是如何工作的,让提问者理解为什么它解决了他们的问题。 – SuperBiasedMan 2015-06-05 15:08:42

+0

这行很关键var fi = new FileInfo(fileName); var length =(int)fi.Length;一旦他知道了这个长度,就可以让他读取该文件中的所有内容。 – user2683973 2015-06-05 19:20:33

+0

是否为共享内存工作? – tofutim 2015-12-01 01:06:08