Vă mulțumim pentru susținere

Citiți fișierul binar într-un struct

Încerc să citesc datele binare folosind C #. Am toate informațiile despre aspectul datelor din fișierele pe care vreau să le citesc. Sunt capabil să citesc datele "bucată pe bucată", adică să primesc primele 40 octeți de date care o convertesc într-un șir, să obțin următoarele 40 de octeți.

Întrucât există cel puțin trei versiuni ușor diferite ale datelor, aș dori să citesc datele direct într-un struct. Simt doar mult mai mult decât căutând-o "pe linie".

Am încercat următoarea abordare, dar fără nici un folos:

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();

Fluxul este un FileStream deschis de la care am început să citesc. Obțineți un AccessViolationExceptio n când utilizați Marshal.PtrToStructure .

Fluxul conține mai multe informații decât încerc să citesc deoarece nu mă interesează datele de la sfârșitul fișierului.

Structura este definită ca:

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

Codul de exemple este modificat de la original pentru a face această întrebare mai scurtă.

Cum aș citi datele binare dintr-un fișier într-un struct?

0
adăugat editat

6 răspunsuri

Nu am avut noroc folosind BinaryFormatter, cred că trebuie să am o structură completă care să se potrivească exact cu conținutul fișierului. Mi-am dat seama că, în cele din urmă, nu m-am interesat prea mult de conținutul fișierului, așa că am mers cu soluția de a citi o parte a fluxului într-un bytebuffer și apoi să îl convertesc folosind

Encoding.ASCII.GetString()

pentru șiruri de caractere și

BitConverter.ToInt32()

pentru numere întregi.

Va trebui să fiu capabil să analizez mai mult fișierul mai târziu, dar pentru această versiune am scăpat cu doar câteva linii de cod.

0
adăugat

Citirea direct în structuri este rău - multe dintre programele C au căzut din cauza ordinelor diferite de octeți, implementări diferite de compilatoare ale câmpurilor, ambalare, dimensiune de cuvânt .......

Ești cel mai bun de a serializa și de a descoperi byte prin byte. Utilizați build-ul în chestii dacă doriți sau pur și simplu să vă obișnuiți cu BinaryReader.

0
adăugat
De asemenea, nu sunt de acord. Când performanța este cheia sau atunci când aveți nevoie de interopul binar C ++ / C #, scrierea structului simplu este calea de parcurs.
adăugat autor Dmitri Nesteruk
Nu sunt de acord, citirea direct în structuri este uneori cea mai rapidă modalitate de a obține datele dvs. într-un obiect utilizabil. Dacă scrieți cod orientat spre performanță, acest lucru poate fi foarte util. Da, trebuie să fiți conștienți de aliniere și ambalare și asigurați-vă că orice mașină cu punct final va folosi același lucru.
adăugat autor Joe

Incearca asta:

using (FileStream stream = new FileStream(fileName, FileMode.Open))
{
    BinaryFormatter formatter = new BinaryFormatter();
    StructType aStruct = (StructType)formatter.Deserialize(filestream);
}
0
adăugat
BinaryFormatter are propriul format pentru datele binare - ceea ce este bine dacă citiți / scrieți datele pe cont propriu. nu este util dacă primiți un fișier dintr-o altă sursă.
adăugat autor russau

Problema este șirul s din structura dvs. Am constatat că tipurile de marshaling cum ar fi byte / short / int nu reprezintă o problemă; dar atunci când aveți nevoie să marshal într-un tip complex, cum ar fi un șir, aveți nevoie de struct dumneavoastră pentru a imita în mod explicit un tip neangajat. Poți să faci asta cu atributul Marshal.

Pentru exemplul dvs., ar trebui să funcționeze următoarele:

[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;
}
0
adăugat

Nu văd nici o problemă cu codul tău.

doar din cap, dar dacă încerci să o faci manual? funcționează?

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));
...
...
...

încercați, de asemenea

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();

apoi utilizați tampon [] în BinaryReader în loc să citiți date din FileStream pentru a vedea dacă totuși obțineți excepția AccessViolation.

Nu am avut noroc folosind   BinaryFormatter, cred că trebuie   aveți un struct complet care se potrivește   exact conținutul fișierului.

Asta are sens, BinaryFormatter are propriul format de date, complet incompatibil cu a ta.

0
adăugat

După cum a spus Ronnie, aș folosi BinaryReader și citesc fiecare câmp individual. Nu găsesc linkul la articol cu ​​această informație, dar sa observat că folosirea lui BinaryReader pentru citirea fiecărui câmp individual poate fi mai rapid decât Marshal.PtrToStruct, dacă structul conține mai puțin de 30-40 de câmpuri. Voi posta linkul la articol când îl găsesc.

The article's link is at: http://www.codeproject.com/Articles/10750/Fast-Binary-File-Reading-with-C

Atunci când marshaling o serie de structuri, PtrToStruct câștigă mai repede de mâna superioară, pentru că vă puteți gândi la numărul de câmp ca câmp * lungime matrice.

0
adăugat
Într-adevăr! Bun găsi :)
adăugat autor nevelis
Tocmai citeam: codeproject.com/KB/files/fastbinaryfileinput.aspx . Este acest articol despre care te gândești? Autorul notează: "Am constatat că, la aproximativ 40 de domenii, rezultatele pentru cele trei abordări au fost aproape echivalente, iar dincolo de aceasta, abordările de citire a blocurilor au câștigat o mână superioară."
adăugat autor Neal Stublen