2009-10-06 16 views
1

J'ai écrit plusieurs ints, char [] s et tel dans un fichier de données avec BinaryWriter en C#. En lisant le fichier dans (en C#) avec BinaryReader, je peux recréer parfaitement toutes les parties du fichier. Cependant, tenter de les relire en C++ donne des résultats effrayants. J'utilisais fstream pour essayer de relire les données et les données ne lisent pas correctement. En C++, j'ai mis en place un fstream avec ios::in|ios::binary|ios::ate et utilisé seekg pour cibler ma position. J'ai alors lu les quatre octets suivants, qui ont été écrits comme l'entier "16" (et lit correctement dans C#). Cela se lit comme 1244780 en C++ (pas l'adresse de la mémoire, j'ai vérifié). Pourquoi cela serait-il? Y a-t-il un équivalent de BinaryReader en C++? Je l'ai remarqué mentionné sur msdn, mais c'est Visual C++ et IntelliSense ne ressemble même pas à C++, pour moi.Y at-il un BinaryReader en C++ pour lire les données écrites à partir d'un BinaryWriter en C#?

Exemple de code pour l'écriture du fichier (C#):

public static void OpenFile(string filename) 
    { 
     fs = new FileStream(filename, FileMode.Create); 
     w = new BinaryWriter(fs); 

    } 

    public static void WriteHeader() 
    { 
     w.Write('A'); 
     w.Write('B'); 
    } 

    public static byte[] RawSerialize(object structure) 
    { 
     Int32 size = Marshal.SizeOf(structure); 
     IntPtr buffer = Marshal.AllocHGlobal(size); 
     Marshal.StructureToPtr(structure, buffer, true); 
     byte[] data = new byte[size]; 
     Marshal.Copy(buffer, data, 0, size); 
     Marshal.FreeHGlobal(buffer); 
     return data; 
    } 

    public static void WriteToFile(Structures.SomeData data) 
    { 
     byte[] buffer = Serializer.RawSerialize(data); 
     w.Write(buffer); 
    } 

Je ne sais pas comment je pourrais vous montrer le fichier de données.

Exemple de lecture des données en arrière (C#):

 BinaryReader reader = new BinaryReader(new FileStream("C://chris.dat", FileMode.Open)); 
     char[] a = new char[2]; 
     a = reader.ReadChars(2); 
     Int32 numberoffiles; 
     numberoffiles = reader.ReadInt32(); 
     Console.Write("Reading: "); 
     Console.WriteLine(a); 
     Console.Write("NumberOfFiles: "); 
     Console.WriteLine(numberoffiles); 

Ce que je veux jouer dans C++. Première tentative (échoue au premier entier):

fstream fin("C://datafile.dat", ios::in|ios::binary|ios::ate); 
char *memblock = 0; 
int size; 
size = 0; 
if (fin.is_open()) 
{ 
    size = static_cast<int>(fin.tellg()); 
    memblock = new char[static_cast<int>(size+1)]; 
    memset(memblock, 0, static_cast<int>(size + 1)); 

    fin.seekg(0, ios::beg); 
    fin.read(memblock, size); 
    fin.close(); 
    if(!strncmp("AB", memblock, 2)){ 
    printf("test. This works."); 
    } 
    fin.seekg(2); //read the stream starting from after the second byte. 
    int i; 
    fin >> i; 

Edit: Il semble que peu importe quel endroit je l'utilise « seekg », je reçois la même valeur exacte.

+0

Pouvez-vous nous montrer un fragment de code (ou code entier) et un exemple de fichier binaire? – coelhudo

+0

J'ai posté du code. Je ne sais pas où je pourrais télécharger le fichier binaire. – Chris

+0

vous lire chris.dat dans votre lecteur C# et datafile.dat dans votre lecteur C++ ... – Pondidum

Répondre

5

Vous vous rendez compte qu'un caractère est en 16 bits en C# plutôt que 8 en C. Cela est dû au fait qu'un caractère en C# est conçu pour gérer du texte Unicode plutôt que des données brutes. Par conséquent, écrire des caractères à l'aide de BinaryWriter entraînera l'écriture d'Unicode plutôt que des octets bruts.

Ceci peut vous avoir conduit à calculer incorrectement le décalage de l'entier. Je vous recommande de regarder le fichier dans un éditeur hexadécimal, et si vous ne pouvez pas résoudre le problème, publiez le fichier et le code ici.

EDIT1
En ce qui concerne votre code C++, ne pas utiliser le >> opérateur de lire à partir d'un flux binaire. Utilisez read() avec l'adresse de l'int que vous voulez lire.

int i; 
fin.read((char*)&i, sizeof(int)); 

EDIT2
lecture d'un flux fermé va aussi entraîner un comportement non défini. Vous ne pouvez pas appeler fin.close() et espérer toujours pouvoir en lire.

+1

Un caractère c/C++ peut gérer unicode sous la forme d'une chaîne utf-8. – anno

3

Cela peut ou non être liés au problème, mais ...

Lorsque vous créez le BinaryWriter, sa valeur par défaut d'écriture char s en UTF-8. Cela signifie que certains d'entre eux peuvent être plus long qu'un octet, rejetant vos recherches.

Vous pouvez éviter cela en utilisant le constructeur à 2 arguments pour spécifier le codage. Une instance de System.Text.ASCIIEncoding serait la même que celle utilisée par défaut par C/C++.

+0

Le problème avec 'ASCIIEncoding' est qu'il corrompt silencieusement les caractères non ASCII. – CodesInChaos

+0

Vous ne devez JAMAIS C# 's type de chaîne pour un tel interop. À moins que vous ne sachiez ce que vous faites ce qui n'est pas le cas maintenant. Utilisez l'octet []. Même les programmeurs avancés comme moi ont peur du type String. Utilisez les variantes Ecoding pour convertir une chaîne en Byte Array, puis écrivez sa taille et ses données. Lisez-le en C++ en utilisant l'approche de Yacoby, et de la bibliothèque Unicode, comme icu. –

1

Si cela aide, j'ai analysé comment BinaryWriter écrit les données here.

Il a été un certain temps, mais je vais le citer et nous espérons qu'il est précis:

  • Int16 est écrit 2 octets et rembourré.
  • Int32 est écrit comme Little Endian et zéro rembourré
  • Flotteurs sont plus compliquées: il prend la valeur de flotteur et déréférence il, obtenir le contenu de l'adresse de mémoire qui est une hexadécimal
+0

L'int32 étant petit endian et 0 rembourré, cela pourrait-il causer quelques problèmes? Pouvez-vous élaborer du tout? (Désolé, nous n'avons pas encore vérifié le lien.) – Chris

+0

On dirait que c'est lié au caractère C++ et pas aux entiers, sauf pour le décalage –

+0

La page est introuvable. –

1

Il y a beaucoup de chose qui ne va pas dans votre extrait C++. Vous ne devriez pas mélanger la lecture binaire avec la lecture formatée:

// The file is closed after this line. It is WRONG to read from a closed file. 
    fin.close(); 

    if(!strncmp("AB", memblock, 2)){ 
    printf("test. This works."); 
    } 

    fin.seekg(2); // You are moving the "get pointer" of a closed file 
    int i; 

    // Even if the file is opened, you should not mix formatted reading 
    // with binary reading. ">>" is just an operator for reading formatted data. 
    // In other words, it is for reading "text" and converting it to a 
    // variable of a specific data type. 
    fin >> i; 
+0

Merci beaucoup. Je n'ai pas travaillé avec ce genre de choses depuis longtemps et j'ai besoin de ceux-ci souligné :) – Chris

Questions connexes