Lire un fichier binary dans une structure

J’essaie de lire les données binarys en utilisant C #. J’ai toutes les informations sur la mise en page des données dans les fichiers que je veux lire. Je suis capable de lire les données “chunk by chunk”, c.-à-d. Obtenir les 40 premiers octets de données en le convertissant en chaîne, obtenir les 40 prochains octets.

Puisqu’il existe au moins trois versions légèrement différentes des données, j’aimerais lire les données directement dans une structure. Cela semble juste beaucoup plus juste que de le lire “ligne par ligne”.

J’ai essayé l’approche suivante mais en vain:

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

Le stream est un FileStream ouvert à partir duquel j’ai commencé à lire. Je reçois un AccessViolationExceptio n lors de l’utilisation de Marshal.PtrToStructure .

Le stream contient plus d’informations que j’essaie de lire car je ne suis pas intéressé par les données à la fin du fichier.

La structure est définie comme:

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

Le code des exemples est changé de l’original pour raccourcir cette question.

Comment pourrais-je lire les données binarys d’un fichier dans une structure?

Le problème est la chaîne de caractères de votre structure. J’ai trouvé que les types de marshaling comme byte / short / int ne sont pas un problème; mais lorsque vous avez besoin de classer dans un type complexe tel qu’une chaîne, vous avez besoin de votre structure pour imiter explicitement un type non géré. Vous pouvez le faire avec les MarshalAs atsortingb.

Pour votre exemple, les éléments suivants devraient fonctionner:

 [StructLayout(LayoutKind.Explicit)] struct StructType { [FieldOffset(0)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] public ssortingng FileDate; [FieldOffset(8)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] public ssortingng FileTime; [FieldOffset(16)] public int Id1; [FieldOffset(20)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 66)] //Or however long Id2 is. public ssortingng Id2; } 

Voici ce que j’utilise.
Cela a fonctionné avec succès pour lire le format exécutable portable.
C’est une fonction générique, donc T est votre type de struct .

 public static T ByteToType(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; } 

Comme l’a dit Ronnie, j’utiliserais BinaryReader et je lirais chaque champ individuellement. Je ne trouve pas le lien vers l’article avec cette information, mais il a été observé que l’utilisation de BinaryReader pour lire chaque champ individuel peut être plus rapide que Marshal.PtrToStruct, si la structure contient moins de 30 à 40 champs. Je posterai le lien vers l’article quand je le trouverai.

Le lien de l’article est à l’ adresse : http://www.codeproject.com/Articles/10750/Fast-Binary-File-Reading-with-C

Lors du marshaling d’un tableau de structures, PtrToStruct gagne plus rapidement, car vous pouvez considérer le nombre de champs comme des champs * longueur du tableau.

Je n’ai pas eu de chance d’utiliser le BinaryFormatter, je suppose que je dois avoir une structure complète qui corresponde exactement au contenu du fichier. Je me suis rendu compte qu’en fin de compte je n’étais pas du tout intéressé par le contenu du fichier, alors je suis allé avec la solution de lire une partie du stream dans un bytebuffer et de le convertir en utilisant

 Encoding.ASCII.GetSsortingng() 

pour les cordes et

 BitConverter.ToInt32() 

pour les entiers.

Je devrai pouvoir parsingr plus de fichiers plus tard, mais pour cette version, je me suis contenté de quelques lignes de code.

Je ne vois aucun problème avec votre code.

juste hors de ma tête, et si vous essayez de le faire manuellement? est-ce que ça marche?

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

Essayez aussi

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

puis utilisez buffer [] dans votre BinaryReader au lieu de lire les données de FileStream pour voir si vous obtenez toujours une exception AccessViolation.

Je n’ai pas eu de chance d’utiliser le BinaryFormatter, je suppose que je dois avoir une structure complète qui corresponde exactement au contenu du fichier.

Cela a du sens, BinaryFormatter a son propre format de données, totalement incompatible avec le vôtre.

Essaye ça:

 using (FileStream stream = new FileStream(fileName, FileMode.Open)) { BinaryFormatter formatter = new BinaryFormatter(); StructType aStruct = (StructType)formatter.Deserialize(filestream); } 

La lecture directe des structures est malfaisante – beaucoup de programmes C sont tombés en panne à cause de l’ordre des octets, des implémentations différentes des champs, de la taille des mots, etc.

Vous êtes le meilleur de la sérialisation et de la désérialisation par octet. Utilisez les éléments de construction si vous voulez ou tout simplement vous habituer à BinaryReader.