Есть ли в C ++ BinaryReader для чтения данных, записанных с BinaryWriter в C #? - PullRequest
1 голос
/ 06 октября 2009

Я написал несколько целых, char [] и т. Д. В файл данных с BinaryWriter на C #. Читая файл обратно (в C #) с помощью BinaryReader, я могу прекрасно воссоздать все части файла.

Однако попытка прочитать их обратно с помощью C ++ дает некоторые страшные результаты. Я использовал fstream, чтобы попытаться прочитать данные, а данные не читались правильно. В C ++ я установил fstream с ios::in|ios::binary|ios::ate и использовал seekg для определения местоположения. Затем я прочитал следующие четыре байта, которые были записаны как целое число «16» (и правильно читает в C #). Это читается как 1244780 в C ++ (не адрес памяти, я проверял). С чего бы это? Есть ли эквивалент BinaryReader в C ++? Я заметил, что это упомянуто в msdn, но это Visual C ++, и intellisense для меня даже не выглядит как c ++.

Пример кода для записи файла (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);
    }

Я не уверен, как я могу показать вам файл данных.

Пример чтения данных обратно (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);

Это я хочу выполнить на С ++. Начальная попытка (неудача с первого целого числа):

 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;

Редактировать: Кажется, что независимо от того, в каком месте я использую «seekg», я получаю одно и то же значение.

Ответы [ 4 ]

5 голосов
/ 06 октября 2009

Вы понимаете, что в C # символ состоит из 16 бит, а не 8, как обычно в C. Это потому, что символ в C # предназначен для обработки текста Unicode, а не необработанных данных. Поэтому запись символов с использованием BinaryWriter приведет к записи Unicode, а не необработанных байтов.

Это могло привести к неправильному вычислению смещения целого числа. Я рекомендую вам взглянуть на файл в шестнадцатеричном редакторе, и если вы не можете решить проблему, опубликуйте файл и код здесь.

EDIT1
Что касается вашего кода C ++, не используйте оператор >> для чтения из двоичного потока. Используйте read () с адресом int, который вы хотите прочитать.

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

EDIT2
Чтение из закрытого потока также приведет к неопределенному поведению. Вы не можете вызвать fin.close (), и тогда все еще ожидаете, что сможете читать с него.

3 голосов
/ 06 октября 2009

Это может или не может быть связано с проблемой, но ...

Когда вы создаете BinaryWriter, по умолчанию записывается char s в UTF-8. Это означает, что некоторые из них могут быть длиннее одного байта, отбрасывая ваши поиски.

Этого можно избежать, используя конструктор с двумя аргументами для указания кодировки. Экземпляр System.Text.ASCIIEncoding будет таким же, как тот, который C / C ++ использует по умолчанию.

1 голос
/ 06 октября 2009

В вашем фрагменте C ++ много ошибок. Вы не должны смешивать двоичное чтение с форматированным чтением:

  // 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;
1 голос
/ 06 октября 2009

Если это поможет, я рассказал, как BinaryWriter записывает данные здесь .

Это было давно, но я процитирую это и надеюсь, что это точно:

  • Int16 записывается как 2 байта и дополняется.
  • Int32 записывается как Little Endian и дополняется нулями
  • Число с плавающей запятой сложнее: оно принимает значение с плавающей точкой и разыменовывает его, получая содержимое адреса памяти в шестнадцатеричном формате
...