Lesen Sie Binärdatei in einer Struktur

stimmen
42

Ich versuche, Binärdaten mit C # zu lesen. Ich habe alle Informationen über das Layout der Daten in den Dateien, die wir lesen möchten. Ich bin in der Lage, die Daten „chunk von chunk“ zu lesen, dh die ersten 40 Byte Daten bekommen es in einen String konvertieren, erhalten die nächsten 40 Bytes.

Da es mindestens drei etwas andere Version der Daten ist, würde Ich mag die Daten direkt in eine Struktur lesen. Es fühlt sich einfach so viel mehr Recht, als durch sie „Zeile für Zeile“ zu lesen.

Ich habe den folgenden Ansatz versucht, aber ohne Erfolg:

StructType aStruct;
int count = Marshal.SizeOf(typeof(StructType));
byte[] readBuffer = new byte[count];
BinaryReader reader = new BinaryReader(stream);
readBuffer = reader.ReadBytes(count);
GCHandle handle = GCHandle.Alloc(readBuffer, GCHandleType.Pinned);
aStruct = (StructType) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(StructType));
handle.Free();

Der Strom ist eine geöffnete Filestream aus dem ich begonnen haben , zu lesen , aus. Ich erhalte eine AccessViolationException bei der Verwendung Marshal.PtrToStructure.

Der Strom enthält mehr Informationen als ich versuche, da ich am Ende der Datei in Daten bin nicht daran interessiert zu lesen.

Die Struktur ist so definiert, wie:

[StructLayout(LayoutKind.Explicit)]
struct StructType
{
    [FieldOffset(0)]
    public string FileDate;
    [FieldOffset(8)]
    public string FileTime;
    [FieldOffset(16)]
    public int Id1;
    [FieldOffset(20)]
    public string Id2;
}

Die Beispiele Code wird von der ursprünglichen geändert diese Frage zu verkürzen.

Wie würde ich binäre Daten aus einer Datei in eine Struktur zu lesen?

Veröffentlicht am 05/08/2008 um 15:28
quelle vom benutzer
In anderen Sprachen...                            


7 antworten

stimmen
19

Das Problem ist die Zeichenkette s in Ihrer Struktur. Ich fand , dass Typen wie Byte / short / int ist kein Problem , Marshalling; aber wenn man in einem komplexen Typ wie einen String Marschall benötigen, müssen Sie Ihre Struktur explizit einen nicht verwalteten Typ imitieren. Sie können mit dem MarshalAs attrib dies zu tun.

Für Ihr Beispiel sollte die folgenden Arbeiten:

[StructLayout(LayoutKind.Explicit)]
struct StructType
{
    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
    public string FileDate;

    [FieldOffset(8)]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
    public string FileTime;

    [FieldOffset(16)]
    public int Id1;

    [FieldOffset(20)]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 66)] //Or however long Id2 is.
    public string Id2;
}
Beantwortet am 21/08/2008 um 20:02
quelle vom benutzer

stimmen
8

Hier ist , was ich verwende.
Dieser arbeitete für mich erfolgreich für Portable Executable - Format zu lesen.
Es ist eine generische Funktion, so TSie ist structTyp.

public static T ByteToType<T>(BinaryReader reader)
{
    byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));

    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    handle.Free();

    return theStructure;
}
Beantwortet am 02/11/2010 um 03:40
quelle vom benutzer

stimmen
5

Als Ronnie sagte, würde ich Binary verwenden und jedes Feld einzeln lesen. Ich kann den Link auf den Artikel mit dieser Information finden, aber es ist beobachtet worden, dass Binary mit jedem einzelnen Feld lesen als Marshal.PtrToStruct schneller sein, wenn die Struktur weniger als 30-40 oder so Felder. Ich werde den Link zum Artikel, sobald ich es finde.

Die Verbindung des Artikels ist unter: http://www.codeproject.com/Articles/10750/Fast-Binary-File-Reading-with-C

Wenn eine Reihe von structs Marshalling gewinnt PtrToStruct die Oberhand schneller, weil Sie die Feldanzahl als Felder * Feldlänge denken kann.

Beantwortet am 06/05/2010 um 02:04
quelle vom benutzer

stimmen
3

Ich hatte kein Glück der BinaryFormatter mit, ich glaube, ich habe eine komplette Struktur haben, die den Inhalt der Datei genau übereinstimmt. Ich erkennen, dass ich am Ende war in sehr viel von dem Dateiinhalt sowieso nicht interessiert, damit ich mit der Lösung ging ein Teil des Stroms in einen ByteBuffer von lesen und wandeln sie dann mit

Encoding.ASCII.GetString()

für Streicher und

BitConverter.ToInt32()

für die ganzen Zahlen.

Ich muss in der Lage sein, mehr der Datei später zu analysieren, aber für diese Version habe ich mit nur ein paar Zeilen Code entfernt.

Beantwortet am 06/08/2008 um 10:03
quelle vom benutzer

stimmen
1

Ich sehe kein Problem mit Ihrem Code.

gerade aus meinem Kopf, was passiert, wenn Sie versuchen, es manuell zu tun? funktioniert es?

BinaryReader reader = new BinaryReader(stream);
StructType o = new StructType();
o.FileDate = Encoding.ASCII.GetString(reader.ReadBytes(8));
o.FileTime = Encoding.ASCII.GetString(reader.ReadBytes(8));
...
...
...

probiere auch

StructType o = new StructType();
byte[] buffer = new byte[Marshal.SizeOf(typeof(StructType))];
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Marshal.StructureToPtr(o, handle.AddrOfPinnedObject(), false);
handle.Free();

dann verwenden buffer [] in Ihrer Binary statt Lesen von Daten aus Filestream zu sehen , ob Sie noch Access Exception.

Ich hatte kein Glück der BinaryFormatter mit, ich glaube, ich habe eine komplette Struktur haben, die den Inhalt der Datei genau übereinstimmt.

Das macht Sinn, BinaryFormatter ein eigenes Datenformat hat, völlig unvereinbar mit Ihnen.

Beantwortet am 05/08/2008 um 16:31
quelle vom benutzer

stimmen
0

gerade in structs Lesen ist das Böse - viele ein C-Programm wurde aufgrund der unterschiedlichen Byte Ordnungen gefallen über verschiedene Compiler-Implementierungen von Feldern, Verpackung, Wortgröße .......

Sie sind am besten von Serialisierung und deserialising Byte für Byte. Verwenden Sie den Build in Sachen, wenn Sie wollen oder einfach nur zu Binary gewöhnen.

Beantwortet am 23/09/2008 um 22:43
quelle vom benutzer

stimmen
0

Versuche dies:

using (FileStream stream = new FileStream(fileName, FileMode.Open))
{
    BinaryFormatter formatter = new BinaryFormatter();
    StructType aStruct = (StructType)formatter.Deserialize(filestream);
}
Beantwortet am 05/08/2008 um 15:56
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more