2013-08-16 6 views
2

Прямо сейчас я использую istream для чтения данных. У меня есть и текст, который я хотел бы читать как строки и числа, и хеши, которые считываются в массивы символов. Так как хэши эффективно случайны, я поражаю змеи, когда я пытаюсь прочитать его обратно и попал в EOF (который является частью хэша). Есть ли способ сделать это, не прибегая к страху. Кроме того, есть ли использовать как istream, так и fread, некоторые из них мне не нужны, чтобы разобрать целые числа и строки вручную. Наконец, что лучший способ использовать fgets для получения строки неизвестной длины.Могу ли я читать двоичные данные с istream в C++?

Спасибо, Eric

EDIT: Вот код:

string dummy; 
ifstream in(fileName); 
for(int i=0; i<numVals; i++) 
{ 
    int hashLen; 
    in>>hashLen; 
    char cc; 
    in.get(cc);//Get the space in between 
    cout<<"Got first byte: "<<(int)cc<<endl; 

    char * hashChars = new char[hashLen]; 
    in.read(hashChars, hashLen); 
    for(int j =0; j <hashLen; j++) 
    { 
     char c = hashChars[j]; 
     unsigned char cc = reinterpret_cast<unsigned char&>(c); 
     cout<<"Got byte: "<<(int)c<<(int)cc<<endl; 
     if(in.fail()) 
     { 
      cout<<"Failed! "<<in.eof()<<" "<<in.bad()<<endl; 
     } 
    } 

delete hashChars; 

    getline(in,dummy);//get a dummy line 
    cout<<"Dummy: "<<dummy<<" numvals: "<<numVals<<" i: "<<i<<" hashLength: "<<hashLen<<endl; 
} 

Мой выход выглядит следующим образом:

1> Получил первый байт: 32

1> Got байт: 4 4

1> Байт: -1 4 242

1> Гот байт: 108 108

1> Гот байт: 87 87

1> Гот байт: 113 113

1> Гот байт: -116 140

1> Гот байт: -106 150

1> Гот байт: -35 221

1> Гот байт: 0 0

1> Гот байт: -91 165

1> Гот байт: 39 39

1> Гот байт: 111 111

1> Гот байт: 7 7

1 > Гот байт: 126 126

1> Гот байт: 16 16

1> Гот байт: -42 214

1> Фиктивный: numvals: 35 я: 12 hashLength: 16

1> Получили первые байты: 32

1> Гот байты: 14 14

1> Ошибка! 1 0

1> Got байт: -65 191

1> Ошибка! 1 0

1> Got байт: -107 149

1> Ошибка!1 0

1> Got байт: -44 212

1> Ошибка! 1 0

1> Got байт: -60 196

1> Ошибка! 1 0

1> Got байт: -51 205

1> Ошибка! 1 0

1> Got байт: -51 205

1> Ошибка! 1 0

+0

Образец ваших данных и код, который вы используете для его чтения, будут иметь * длинный * путь в получении ответов на то, что происходит не так. Что касается разбора целых чисел и строк вручную, отформатированные экстракторы с 'istream's - это пижамы для кошек. – WhozCraig

+0

EOF не может быть частью хэша, поскольку EOF - это концепция, которая не может быть встроена в файл. Однако вы читаете данные, это неправильно. –

+0

Да потоки могут читать двоичные данные.Потоки имеют функции для синтаксического анализа целых чисел и строк различной длины. Не используйте fgets, fread или другие c-функции на C++. –

ответ

1

При чтении двоичных данных вы обычно хотите открыть std::ifstream с флагом std::ios_base::binary. Полученные различия довольно малы, но они, как правило, имеют значение.

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

  • Вы всегда нужно проверить после прочтения, если операция прошла успешно, например, с использованием if (in.read(hashChars, hashLen)) { ... }
  • Там нет необходимости для использования reinterpret_cast<...>(), который всегда имеет определенную реализацию, определенную семантикой. Вместо этого вы должны использовать static_cast<unsigned char>(c).
  • Вы выделяете массив символов, но вы отпускаете его, используя delete p. Вместо этого вам нужно использовать delete[] p. Использование delete p приводит к неопределенному поведению. На самом деле нет необходимости использовать new и delete, поскольку std::vector<char> hashChars(hashLen) выполняет автоматическое управление памятью.

Есть несколько [изуродовали] вопросов иначе внедренных в запросе выше (так вопросы/ответы догадки о том, что спрашивают):

  • Вы можете смешать std::istream::read() и fread() на том же stream (я думаю, это вопрос): не сразу, если поток не будет std::cin, который читается из того же источника, что и stdin. Если вы хотите использовать как std::istream::read(), так и fread() в том же файле, вам необходимо обернуть FILE* подходящим std::streambuf и инициализировать std::istream соответствующим объектом.
  • Как читать строку произвольного размера с помощью fgets()? Вы не можете. Буфер до fgets() получает выделение перед попыткой его заполнить и всегда может быть заполнен до достижения новой строки. Однако вы можете использовать std::getline() для чтения произвольной длинной строки. Если вы просто хотите пропустить линию, вы можете использовать in.ignore(std::numeric_limits<std::streamsize>::max(), '\n') при использовании std::istream. Вне рук я не знаю, есть ли аналогичная операция для FILE*.
+0

Спасибо за эти предложения, я забыл о двоичном флаге, который, как представляется, должен быть уверен, что^Z (символ Windows eof) игнорируется. Теперь он читает весь файл. –

Смежные вопросы