Есть ли BinaryReader в C ++ для чтения данных, записанных из BinaryWriter в C #?

StackOverflow https://stackoverflow.com/questions/1525580

Вопрос

Я записал несколько целых чисел, char[]s и тому подобное в файл данных с помощью 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);

Это я хочу выполнить на c ++.Начальная попытка (завершается неудачей при первом целом числе):

 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", я получаю точно такое же значение.

Это было полезно?

Решение

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

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

РЕДАКТИРОВАТЬ 1
Что касается вашего кода на C ++, не используйте оператор >> для чтения из двоичного потока.Используйте read() с адресом int, в который вы хотите выполнить чтение.

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

РЕДАКТИРОВАТЬ 2
Чтение из закрытого потока также приведет к неопределенному поведению.Вы не можете вызвать fin.close() и затем по-прежнему ожидать, что сможете читать из него.

Другие советы

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

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

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

В вашем фрагменте 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;

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

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

  • Int16 записывается в виде 2 байт и дополняется.
  • Int32 записывается как Строчный порядковый номер и дополняется нулем
  • Поплавки более сложны:он принимает значение с плавающей запятой и разыменовывает его, получая содержимое адреса памяти, которое является шестнадцатеричным
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top