2009-06-11 10 views
1

Ist es möglich, nur eine begrenzte Anzahl von Elementen aus einem serialisierten Array zu deserialisieren?Deserialisieren nur der ersten x Elemente eines Arrays

Hintergrund:

Ich habe ein Strom, der Millionen von Artikeln eine serialisierte Array vom Typ T. hält das Array kann, aber ich möchte eine Vorschau auf die Inhalte erstellen und die nur abrufen, sagen wir, ersten hundert Artikel. Meine erste Idee war, einen Wrapper um den Eingabestream zu erstellen, der die Anzahl der Bytes begrenzt, aber es gibt keine direkte Übersetzung von der Anzahl der Elemente des Arrays zur Stream-Größe.

Antwort

1

Nein, dies kann nicht mit Standard-.NET-Serialisierung durchgeführt werden. Sie müssen Ihr eigenes Speicherformat erfinden. Zum Beispiel umfasst einen Header mit Offsets von Datenblöcken:

---------------- 
<magic-value> 
<chunks-count> 
<chunk-size> 
<chunk-1-offset> 
<chunk-2-offset> --+ 
...     | 
---------------- | 
...     | 
<chunk-1>   | 
...     | 
---------------- | 
...    <-+ 
<chunk-2> 
... 
----------------- 
... 

Also, um Daten in der Vorschau (von jeder beliebigen Position) werden Sie höchstens ceil(required-item-count/chunk-size) zu laden haben. Dies wird einige Overhead verursachen, aber es ist viel besser als das Laden der gesamten Datei.

+0

Also muss ich das Array in Chunks speichern und akzeptieren, dass es ein wenig mehr lädt? – Rauhotz

0

Können Sie Ihre Datenquelle möglicherweise ändern, so dass sie eine Datenvorschau in einem anderen Array enthält, das Sie separat deserialisieren können?

1

Was ist der Serializer?

Mit BinaryFormatter wäre das sehr, sehr knifflig.

Mit XML könnten Sie vielleicht die XML vorverarbeiten, aber das ist sehr schwierig.

Andere Serialisierer existieren, obwohl - zum Beispiel, mit Protobuf-Net gibt es wenig Unterschied zwischen einem Array/Liste von Elementen und einer Folge von einzelnen Elementen - so wäre es ziemlich einfach, eine endliche Abfolge von Elementen auszuwählen ohne das gesamte Array zu bearbeiten.


komplettes protobuf-net Beispiel:

[ProtoContract] 
class Test { 
    [ProtoMember(1)] 
    public int Foo { get; set; } 
    [ProtoMember(2)] 
    public string Bar { get; set; } 

    static void Main() { 
     Test[] data = new Test[1000]; 
     for (int i = 0; i < 1000; i++) { 
      data[i] = new Test { Foo = i, Bar = ":" + i.ToString() }; 
     } 
     MemoryStream ms = new MemoryStream(); 
     Serializer.Serialize(ms, data); 
     Console.WriteLine("Pos after writing: " + ms.Position); // 10760 
     Console.WriteLine("Length: " + ms.Length); // 10760 
     ms.Position = 0; 
     foreach (Test foo in Serializer.DeserializeItems<Test>(ms, 
       PrefixStyle.Base128, Serializer.ListItemTag).Take(100)) { 
      Console.WriteLine(foo.Foo + "\t" + foo.Bar); 
     } 
     Console.WriteLine("Pos after reading: " + ms.Position); // 902 

    } 
} 

Beachten Sie, dass DeserializeItems<T> ist ein faules/Streaming-API, so dass es verbraucht nur Daten aus dem Stream, wie Sie über sie iterieren - daher die LINQ Take(100) vermeiden uns den ganzen Strom lesen.

+0

Würde ein bisschen Hacker, der die ISerializable-Schnittstelle implementiert, ihn nicht bekommen, was er will? – Noldorin

+0

@Noldorin - nicht so weit ich weiß ... Sie können die Array-Deserialisierung nicht abfangen, egal wie Sie mit jedem einzelnen Objekt umgehen (via ISerializable) –

Verwandte Themen