Возникли проблемы с символом 0x0A в C++ даже в двоичном режиме. (интерпретирует это как новый файл)

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

Файлы содержат имена, упорядоченные по рангу, но между каждым именем есть 7 случайных контрольных кодов (явно непечатаемых). Текстовый файл выглядит так:

..C...hName1..)...&Name2......)Name3..é...þName4..Ü...†Name5..'...QName6..~... bName7..H...NName8..|....Name9..v...HName10.

Проверил через hexEditor и увидел, что первый управляющий код после каждого имени всегда нулевой символ (0x00). Итак, что я делаю, так это читаю все, а затем вычисляю каждый символ. Когда найден символ 0x00, пропустите 7 символов и продолжайте поиск. Таким образом, вы в конечном итоге со списком, не так ли?

Сначала у меня была проблема, что в этих случайных управляющих кодах иногда можно было найти "мягкий EOF" (0x1A), и программа переставала там читать. Так что я, наконец, решил открыть его в бинарном режиме. Это сработало, и тогда все было бы засчитано... по крайней мере, я так думал.

Но я наткнулся на другой файл, который все еще не работал, и, наконец, обнаружил, что там был символ EOF! (0x0A) Что не имеет смысла, так как я открываю его в двоичном режиме. Но тем не менее, после прочтения этого символа C++ интерпретирует его как новый файл и, следовательно, пропускает 7 символов, поэтому имя после этого символа всегда будет отображаться как обрезанное.

Вот мой текущий код:

#include <cstdlib>
#include <iostream>
#include <fstream>
using namespace std;


int main () {
  string scores;
  system("wget http://certainwebsite/001.txt"); //download file
  ifstream highin ("001.txt", ios::binary);
  ofstream highout ("board.txt", ios::binary);
  if (highin.is_open())
  {
    while ( highin.good() )
    {
          getline (highin, scores);
          for (int i=0;i<scores.length(); i++)
          {
              if (scores[i]==0x00){
                 i=i+7; //skip 7 characters if 'null' is found
                 cout << endl;
                 highout << endl;
                 }
              cout << scores[i];
              highout << scores[i]; //cout names and save them in output file
          }
    }
    highin.close();
  }
  else cout << "Unable to open file";
  system("pause>nul");
}

Не знаю, как игнорировать этот символ, если он уже в двоичном режиме не работает. Извините за длинный вопрос, но я хотел быть подробным и конкретным. В этом случае символ EOF располагается перед Name3, поэтому вывод выглядит следующим образом: http://i.imgur.com/yu1NjoZ.png


person F.Webber    schedule 26.05.2013    source источник
comment
Будьте осторожны при увеличении i, он может пройти за конец счета, если буфер короче, чем ожидалось... похоже, проблема в getline. Попробуйте использовать неформатированные функции ввода istreams   -  person nishantjr    schedule 26.05.2013
comment
0x0A не является символом EOF. Это символ конца строки, ASCII LF или '\n'. getline() распознает его как маркер конца строки. Если вы не хотите специально обрабатывать символы '\n', getline, вероятно, не подходит для использования.   -  person Keith Thompson    schedule 26.05.2013


Ответы (3)


По умолчанию getline() читает до конца строки и отбрасывает символ новой строки. Однако символ-разделитель можно настроить (указав третий параметр). Если вы хотите читать до нулевого символа (не до конца строки), вы можете попробовать использовать getline (highin, scores, '\0'); (и настроить логику пропуска символов).

person heap underrun    schedule 26.05.2013

Я рад, что вы это поняли, и меня не удивляет, что виноват getline(). У меня была аналогичная проблема с символом новой строки, когда я пытался прочитать файл CSV. В С++ существует несколько различных функций getline() в зависимости от того, как вы вызываете функцию, и каждая из них по-разному обрабатывает символ новой строки.

В качестве примечания, в вашем цикле for я бы рекомендовал не выполнять вызов метода в вашем тесте. Это добавляет ненужные накладные расходы в цикл. Было бы лучше вызвать метод один раз и поместить это значение в переменную, затем войти в цикл и проверить i на соответствие переменной длины. Если вы не ожидаете, что длина изменится, вызов метода length() на каждой итерации будет пустой тратой системных ресурсов.

person Richard D    schedule 27.05.2013
comment
О, я не подумал об этом, спасибо за подсказку. Теперь это реализовано. - person F.Webber; 28.05.2013

Спасибо всем, ребята, это сработало, именно getline() действительно доставлял мне проблемы. Из-за цикла «пока» каждый раз, когда он находил новый символ строки, он перезапускал процесс, поэтому эти 7 символов пропускались.

person F.Webber    schedule 27.05.2013
comment
Добро пожаловать в СО! Вы должны принять этот ответ, если он был вам полезен. В противном случае вы должны предоставить немного более подробный ответ, объясняющий вашу проблему. - person awesoon; 27.05.2013
comment
Спасибо, я еще не освоился с функцией принятия ответов, но теперь я ;) Принято. - person F.Webber; 28.05.2013