2013-02-19 30 views
6

Potrzebuję czegoś podobnego do ReadToEnd lub ReadAllBytes, aby odczytać całą zawartość pliku MemoryMappedFile za pomocą MappedViewAccessor, jeśli nie znam rozmiaru to, jak mogę to zrobić?Odczytaj całą zawartość pliku mapowanego w pamięci lub widoku mapowanego widoku widoku pamięci, nie znając jego rozmiaru.

Szukałem dla niej, widziałem to pytanie, ale nie jest to rzeczą szukam:

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

Edit:

Jest problem, (int) stream.Length nie podaje mi prawidłowej długości, raczej podaje rozmiar użytego wewnętrznego bufora! Muszę odświeżyć to pytanie, ponieważ jest bardzo pilne.

+1

nie widzę tego jako ważnego pytanie ... po prostu jak firmware rozmiarze pasującym do regionów pamięci dane muszą mieścić się wewnątrz wyznaczony powierzchnia. Masz rozmiar utworzonego pliku, jeśli nie masz tego rozmiaru, to musisz go dostarczyć lub znać przed rozpoczęciem pracy z plikiem przez abstrakcję lub API. Można także utworzyć nagłówek w pliku odwzorowanym w pamięci, aby wskazać długość i bieżące przesunięcie, jeśli jest to wymagane. Na przykład, jeśli rozmiar pliku jest mniejszy niż rozmiar strony i piszę do obszaru po twoim rozmiarze .. – Jay

Odpowiedz

11

Zamiast używać strumienia:

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 jest moim młodszym bratem, ma 19 lat, zawsze jest ratownikiem !!! thankx Amer;) –

+0

Odpowiedź ma pewne problemy, proszę podać lepszą odpowiedź. –

+0

Niesamowite, nie znalazłem żadnego problemu z odczytaniem/zapisaniem strun w ten sposób, te zaokrąglone 4096 bajtów wychodzą podczas pobierania bajtów. naprawdę bardzo przydatne rozwiązanie. – ElektroStudios

5

Nie można tego zrobić.

Akcesorium widoku jest tworzone z minimalnym rozmiarem strony systemowej, co oznacza, że ​​może być większy niż rzeczywisty plik. Strumień widoków jest tylko formą strumienia akcesora, więc daje to samo zachowanie.

„poglądy są w jednostkach stron systemowych, a wielkość widoku jest zaokrąglana w górę do najbliższego systemu rozmiaru strony”

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

akcesor chętnie czytać i pisz poza rzeczywistym plikiem bez zgłaszania wyjątku. Podczas czytania wszystkie bajty poza plikiem będą miały wartość zero. Podczas zapisu bajty zapisane poza plikiem są po prostu ignorowane.

Aby odczytać plik z pliku zmapowanego w pamięci z dokładnym rozmiarem oryginalnego pliku, należy już znać ten rozmiar.

+0

Co sugerujesz dla IPC? dodać trochę ogona do pliku? albo co? –

+0

Zastanawiam się nad wielkością pliku na początku. –

+0

@MohamedSakherSawan: Tak, każda struktura plików, w której dane w samym pliku mogą zostać użyte do określenia rozmiaru, zadziała. – Guffa

6

To jest trudno odpowiedzieć, ponieważ istnieje jeszcze wiele szczegółów z aplikacji, które nie zostały wymienione, ale myślę, że zarówno Guffa i odpowiedzi Amer są nadal częściowo słuszne:

  • MemoryMappedFile jest więcej pamięci niż plik; jest to sekwencja stron o wielkości 4 KB w pamięci. Zatem stream.Length da ci wszystkie bajty (nie ma "wewnętrznego rozmiaru bufora"), ale może dać ci więcej bajtów, niż się spodziewasz, ponieważ rozmiar zawsze będzie zaokrąglany do granicy 4Kb.
  • Semantyzm "plikowy" pochodzi z powiązania pliku MemoryMappedFile z rzeczywistym plikiem systemu plików. Zakładając, że proces, który tworzy plik, zawsze dostosowuje rozmiar pliku, możesz uzyskać dokładny rozmiar pliku za pośrednictwem fileSystem.

Jeżeli wszystkie powyższe pasowałby swoją aplikację, a następnie dodaje powinno działać:

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

Aby zapisać dane, można użyć to:

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

Ale przez czas, w którym wykonujesz wszystkie powyższe czynności, możesz równie dobrze wykorzystać plik bezpośrednio i uniknąć mapowania pamięci. Jeśli mapowanie go do systemu plików jest niedopuszczalne, odpowiedź Guffy na kodowanie długości (lub markera końcowego) w samych danych jest prawdopodobnie najlepsza.

+0

Nie trzeba pobierać pliku FileInfo (nazwa_pliku). Długość CreateFromFile internaly powoduje, że pojemność pliku odwzorowanego w pamięci jest zgodna z rozmiarem pliku. Po prostu podaj 0 jako rozmiar. –

0

Tylko rozwiązanie @Amer Sawan tłumaczona na 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

chciałbym mieć coś z MemoryStream .ToArray() w celu powrotu wszystkich bajtów, a poniższy kod działa dla mnie:

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

Pozdrawiam!

klasa
0

Zastosowanie FileInfo aby uzyskać długość jak pokazano poniżej

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

Jeśli to możliwe, wyjaśnij nieco więcej, jak działa ten kod dla osoby pytającej, aby zrozumieć, dlaczego rozwiązuje ona ich pytanie. – SuperBiasedMan

+0

Wiersz ten ma kluczowe znaczenie var fi = new FileInfo (fileName); var length = (int) fi.Length; Gdy tylko pozna długość, pozwoli mu na odczytanie wszystkiego w tym pliku. – user2683973

+0

czy to działa dla pamięci współdzielonej? – tofutim