бинарный файл с ++ - PullRequest
       11

бинарный файл с ++

2 голосов
/ 02 декабря 2011

В попытке переработать мою логику в ответ на этот вопрос.Я решил сериализовать объекты буфера протокола, используя пары message-size + protobuf-object-after-SerializeToArray (не волнуйтесь, если вы не понимаете, о чем я говорю).Во всяком случае, моя реализация не работает.Поэтому я решил посмотреть, как работает c ++ fstream.Это семантический кошмар, я не могу быть уверен, нужно ли мне использовать seekg для изменения положения ручки после каждого чтения (или, возможно, даже после каждой записи).Я использую только методы write () и get ().Следующая придуманная программа не работает, почему она не работает, и мне нужно искать в этом контексте?

#include <fstream>
#include <boost/cstdint.hpp>
#include <iostream>

void write()
{
  boost::uint8_t one = (boost::uint32_t )255;
  boost::uint8_t two = (boost::uint32_t) 254;
  boost::uint8_t three =(boost::uint32_t) 253;

  std::fstream file("test", std::fstream::out | std::fstream::binary | std::fstream::trunc);

  file.write( (char *) &one, sizeof(one));
  file.write( (char *) &two, sizeof(two));
  file.write( (char *) &three, sizeof(two));

  std::cout << file.tellg() << std::endl;
  file.flush();
  file.close();
}

void read()
{
  boost::uint8_t one=0;
  boost::uint8_t two=0;
  boost::uint8_t three=0;

  std::fstream file("test", std::fstream::in | std::fstream::binary);


  file.get((char *) & one, sizeof(one)); 
  file.get((char *) & two, sizeof(two)); 
  file.get((char *) & three, sizeof(three)); 

  std::cout << file.tellg() << std::endl;

  std::cout << (boost::uint32_t) one << ":" << (boost::uint32_t) two  << ":" << (boost::uint32_t)three<< std::endl;
  file.close();
}


int main()
{
  write();
  read();  
}

Вывод:

3
-1
0:0:0

C ++ бинарный файл io вызывает у меня грусть и глупость: (

Ответы [ 3 ]

4 голосов
/ 02 декабря 2011

Вместо istream :: get , вы должны использовать istream :: read .

Первый извлекает символы до тех пор, пока один из (n - 1) символов не будетизвлечен или найден символ-разделитель.Последний просто читает неформатированные данные из файла.

2 голосов
/ 02 декабря 2011

fstream::get() специально для текста. Ожидается, что параметр размера будет учитывать конечный ноль в буфере. Передайте sizeof(one) + 1 как размер. Это также прекратит чтение на '\n'. Вы можете изменить символ, который считается разделителем, но не похоже, что вы можете использовать «без разделителя, пожалуйста». Если вам нужны необработанные двоичные данные, используйте fstream::read().

При чтении отдельных байтов вы также можете использовать

one = (boost::uint8_t) file.get();
two = (boost::uint8_t) file.get();
three = (boost::uint8_t) file.get();

Но это, естественно, не годится для данных размером> 1. Вам понадобится fstream::read() для них.

file.read((char *) & one, sizeof(one));
file.read((char *) & two, sizeof(two));
file.read((char *) & three, sizeof(three));

Результат:

3
3
255:254:253
1 голос
/ 02 декабря 2011

istream::get не предназначен для двоичного ввода-вывода, но для текстового ввода-вывода. В частности, file.get(ptr, n) читает строку C, то есть читает не более n-1 символов, а затем завершается нулем. Более того, чтение прекратится, если вы когда-нибудь встретите '\n' в вашем потоке (а не то, что вы хотите в бинарном вводе / выводе). Обратите внимание, что если вы проверяли состояние потока (всегда хорошая идея при вводе / выводе), вы обнаружите, что первая попытка чтения уже привела к ошибке.

Вместо этого вы должны использовать read и write для двоичного ввода-вывода (или, альтернативно, работать с соответствующими потоковыми буферами напрямую).

...