Διαβάστε δυαδικό αρχείο σε ένα struct

ψήφοι
42

Προσπαθώ να διαβάσω δυαδικά δεδομένα χρησιμοποιώντας C #. Έχω όλες τις πληροφορίες σχετικά με τη διάταξη των δεδομένων στα αρχεία που θέλετε να διαβάσετε. Είμαι σε θέση να διαβάσει το «κομμάτι με κομμάτι» των δεδομένων, δηλαδή να πάρει τα πρώτα 40 byte δεδομένων μετατροπή του σε μια σειρά, να πάρει τα επόμενα 40 bytes.

Δεδομένου ότι υπάρχουν τουλάχιστον τρεις ελαφρώς διαφορετική εκδοχή των δεδομένων, θα ήθελα να διαβάσει τα δεδομένα απευθείας σε ένα struct. Είναι ακριβώς αισθάνεται πολύ πιο σωστά από ό, τι κατά την ανάγνωση «γραμμή προς γραμμή».

Έχω δοκιμάσει την ακόλουθη προσέγγιση, αλλά χωρίς αποτέλεσμα:

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

Το ρεύμα είναι μία ανοικτή FileStream από την οποία έχω άρχισε να διαβάζει από το. Παίρνω ένα AccessViolationException κατά τη χρήση Marshal.PtrToStructure.

Η ροή περιέχει περισσότερες πληροφορίες από ό, τι προσπαθώ να διαβάσω επειδή δεν είμαι ενδιαφέρονται για τα στοιχεία στο τέλος του αρχείου.

Το struct ορίζεται όπως:

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

Ο κωδικός παραδείγματα αλλάζει από το αρχικό για να κάνει αυτή την ερώτηση μικρότερη.

Πώς θα διαβάσει δυαδικά δεδομένα από ένα αρχείο σε ένα struct;

Δημοσιεύθηκε 05/08/2008 στις 15:28
πηγή χρήστη
Σε άλλες γλώσσες...                            


7 απαντήσεις

ψήφοι
19

Το πρόβλημα είναι η συμβολοσειρά s σε struct σας. Βρήκα ότι παράταξης τύπους σαν byte / μικρή / int δεν είναι πρόβλημα? αλλά όταν θα πρέπει να συγκεντρώσει σε ένα σύνθετο τύπο, όπως μια σειρά, θα πρέπει να έχετε struct σας για να μιμηθεί ρητά ένα μη διαχειριζόμενο τύπου. Μπορείτε να το κάνετε αυτό με την attrib MarshalAs.

Για παράδειγμα σας, τα ακόλουθα θα πρέπει να εργαστεί:

[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;
}
Απαντήθηκε 21/08/2008 στις 20:02
πηγή χρήστη

ψήφοι
8

Εδώ είναι αυτό που χρησιμοποιώ.
Αυτό λειτούργησε με επιτυχία για μένα και για την ανάγνωση Portable Εκτελέσιμα μορφή.
Είναι μια γενική συνάρτηση, έτσι Tείναι το structείδος.

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;
}
Απαντήθηκε 02/11/2010 στις 03:40
πηγή χρήστη

ψήφοι
5

Όπως είπε ο Ronnie, είχα χρησιμοποιήσει BinaryReader και διαβάστε κάθε τομέα ξεχωριστά. Δεν μπορώ να βρω το σύνδεσμο για το άρθρο με αυτές τις πληροφορίες, αλλά έχει παρατηρηθεί ότι η χρήση BinaryReader να διαβάσει κάθε επιμέρους τομέα μπορεί να είναι ταχύτερη από ό, τι Marshal.PtrToStruct, αν το struct περιέχει λιγότερο από 30-40 ή έτσι πεδία. Θα πάρω μετά τη σύνδεση με το άρθρο όταν το βρείτε.

Σύνδεση του αντικειμένου είναι: http://www.codeproject.com/Articles/10750/Fast-Binary-File-Reading-with-C

Όταν παράταξης μια σειρά από Δομές, PtrToStruct κερδίζει το πάνω χέρι πιο γρήγορα, επειδή μπορείτε να σκεφτείτε την καταμέτρηση τομέα ως πεδία * μήκος σειρά.

Απαντήθηκε 06/05/2010 στις 02:04
πηγή χρήστη

ψήφοι
3

Δεν είχα καμία τύχη με τη χρήση του BinaryFormatter, υποθέτω ότι πρέπει να έχουμε μια πλήρη struct που ταιριάζει με το περιεχόμενο του αρχείου ακριβώς. Συνειδητοποίησα ότι στο τέλος δεν ήμουν ενδιαφέρονται πολύ για το περιεχόμενο του αρχείου έτσι κι αλλιώς έτσι πήγα με τη λύση της ανάγνωσης μέρος του ρεύματος σε ένα bytebuffer και στη συνέχεια να το μετατρέψει χρησιμοποιώντας

Encoding.ASCII.GetString()

για έγχορδα και

BitConverter.ToInt32()

για τους ακέραιους αριθμούς.

Θα πρέπει να είναι σε θέση να αναλύσει περισσότερο από το αρχείο αργότερα, αλλά για αυτή την έκδοση πήρα μακριά με μόλις δύο γραμμές κώδικα.

Απαντήθηκε 06/08/2008 στις 10:03
πηγή χρήστη

ψήφοι
1

Δεν βλέπω κανένα πρόβλημα με τον κωδικό σας.

ακριβώς έξω από το κεφάλι μου, τι αν προσπαθήσετε να το κάνετε μόνοι σας; λειτουργεί?

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

επίσης να δοκιμάσετε

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

στη συνέχεια, χρησιμοποιήστε buffer [] στο BinaryReader σας, αντί της ανάγνωσης δεδομένων από το FileStream για να δείτε αν εξακολουθείτε να έχετε AccessViolation εξαίρεση.

Δεν είχα καμία τύχη με τη χρήση του BinaryFormatter, υποθέτω ότι πρέπει να έχουμε μια πλήρη struct που ταιριάζει με το περιεχόμενο του αρχείου ακριβώς.

Αυτό είναι λογικό, BinaryFormatter έχει τη δική του μορφή των δεδομένων του, εντελώς ασύμβατη με τα δικά σας.

Απαντήθηκε 05/08/2008 στις 16:31
πηγή χρήστη

ψήφοι
0

Ανάγνωση κατ 'ευθείαν σε Δομές είναι κακό - πολλές ένα πρόγραμμα C έχει πέσει λόγω των διαφορετικών orderings byte, διαφορετικές εφαρμογές compiler πεδίων, τη συσκευασία, μέγεθος λέξης .......

Είστε καλύτερο από serialising και deserialising byte με byte. Χρησιμοποιήστε την κατασκευή στην ουσία, αν θέλετε ή απλά να το συνηθίσεις BinaryReader.

Απαντήθηκε 23/09/2008 στις 22:43
πηγή χρήστη

ψήφοι
0

Δοκιμάστε αυτό:

using (FileStream stream = new FileStream(fileName, FileMode.Open))
{
    BinaryFormatter formatter = new BinaryFormatter();
    StructType aStruct = (StructType)formatter.Deserialize(filestream);
}
Απαντήθηκε 05/08/2008 στις 15:56
πηγή χρήστη

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