На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Считывание из текстового файла, используя fstream и перегрузку >>, <<
    Всем хай! Сходу к делу!
    Есть текстовый файл. Там по идее должны быть целые числа, разделенные, например пробелом или табуляцией. Если встречается не число, то обработку нужно прекращать.

    Написал прожку, которая прекрасно работает, если будут числа. Если встречается строка, то программа зацикливается.
    Подскажите, как быть то?

    ExpandedWrap disabled
      const int N = 100;
      int main()
      {
          setlocale(LC_ALL, "");
          
          char nameFile[N];
          cout << "Введите название файла для обработки: ";
          cin.getline(nameFile, N - 1);
          fstream f;
          f.open(nameFile, ios::in);
          if (f.is_open() == false)
              cout << "Ошибка открытия файла!";
          else
          {
              int x;
              //cin.exceptions(ifstream::failbit | ifstream::badbit); - не помогло
              while (f.eof() == false)
              {
                  try
                  {
                      f >> x;
                  }
                  //catch (ifstream::failure e)
                  catch(...)  // не реагирует
                  {
                      cout << endl << endl << "Случилась страшная ошибка!\n\n";
                  }
                  cout << x << '\t';
              }
          }
          cout << endl << endl;
          f.close();
          system("pause");
          return 0;
      }
      Цитата FasterHarder @
      catch(...) // не реагирует

      И не должен
      ExpandedWrap disabled
        if (f >> x)
        {
         
        }
        else
        {
         
        }

      RTFM

      Добавлено
      Альтернативный вариант с исключениями http://en.cppreference.com/w/cpp/io/basic_ios/exceptions
      Сообщение отредактировано: shm -
        shm, спс, ясно, значит блок try-catch вообще тут не нужен, а это очень хАрошо...
          Тут еще проблема возникла)

          Есть текстовый файл, в котором "спрятан" двумерный массив. Могут быть пустые строки + любое количество пробелов и табуляций в любом месте.
          Типа нужно узнать, можно ли получить матрицу из этого файла. Очевидно, что кол-во элементов в каждой строке матрицы должно быть одинаковым.

          Такое достаточно просто реализовать в стиле С, используя strtok, но нужно все через потоки o/i/fstream(, которые плоховато знаю, т к мало их практикую!

          И я вот чегот не выкупаю логику. В принципе, нужно сначала получить кол-во элементов для 1-й строки, чтобы потом можно было сверять их кол-во с остальными.
          В примере выше было показано, как считать числа из файла. При этом пропускаются/игнорируются пробелы, табуляции и переход на новую строку. В ДАННОМ считывании это нужно учитывать. Вот какие методы в этом могут помочь, там их полно. Тупо я не знаю мат.часть этой обработки хорошо, т е какие методы применять, в каком порядке и пр.

          подскажите, а...
            Ну, тебе не надо учитывать разделители. Нужно лишь выделять новую строку. Чтение строки в массив – метод std::istream<>::getline(), чтение строки в std::string – функция std::getline(). Из массива ты можешь по старинке strtok()нуть, из std::string ты можешь создать опять-таки поток std::istringstream, вводить из которого тем же operator>>().
              Qraizer, уже стало понятнее.
              вот, что получилось:
              ExpandedWrap disabled
                void CheckFile(char* pnameFile)
                {
                    fstream f;
                    f.open(pnameFile, ios::in);
                    while (f.eof() == false)    // пока не достигнут конец файла
                    {
                        string currentString;
                        getline(f, currentString);  // получили текущую строку из файла
                        if (currentString.length == 0)  // пустая строка, т е нет ни одного символа
                            continue;
                        // создаем поток из строки
                        std::stringstream ss;
                        ss << currentString;    // записали строку в поток
                 
                        while (ss.eof() == false)   // пока не дошли до конца текущей строки
                        {
                            int val;
                            ss >> val;  // читаем очередное целое число, пропуская пробелы и табуляции
                            cout << val << '\t';
                 
                        }
                        cout << currentString << endl;
                    }
                    f.close();
                }

              компиляция выдает одну ошибку...

              Но мне главное понять логику, т е в целом тут все на своем месте или вообще не так??
                В целом верно. (Ошибка, по ходу, в 9-й строке: std::string::length() – это метод.)
                Я бы чтение с контролем написал примерно так:
                ExpandedWrap disabled
                    std::ifstream inFile(/*...*/);
                    std::string   buf;
                   
                    std::vector<std::vector<int>> vv;     // целевая матрица
                    int row_size = -1;
                   
                    while (inFile.good())
                    {
                      std::getline(inFile, buf);
                      if (!(inFile.good() || inFile.eof() && !buf.empty())) continue;
                   
                      std::istringstream line(buf);
                      std::vector<int>   row((std::istream_iterator<int>(line)), std::istream_iterator<int>());
                   
                      if (row_size == -1) row_size = row.size();
                        else if (row_size != row.size()) throw std::runtime_error("row `" + buf + "` is inconsistent to prev");
                      vv.emplace_back(std::move(row));
                    }
                и ещё можно соптимизировать чуток. Возможно, слишком сложно написано, можно упростить.
                  Цитата Qraizer @
                  В целом верно. (Ошибка, по ходу, в 9-й строке: std::string::length() – это метод.)

                  :yes: ты абсолютно прав! в общем как и всегда...

                  Цитата Qraizer @
                  Я бы чтение с контролем написал примерно так:

                  я бы тоже, если бы знал С++ на твоем уровне ;)
                  Ты прекрасно владеешь мат.частью (просто виртуозно) и имеешь колоссальнейшую вариативность в реализации.

                  Цитата Qraizer @
                  и ещё можно соптимизировать чуток. Возможно, слишком сложно написано, можно упростить.

                  нет-нет, нормально. Сложно только нубам, типа меня.

                  В общем у меня все получилось "моим" способом.
                  Огромное спс Qraizer за помощь!

                  Скрытый текст
                  P.S. в С++ нет ничего сверхсложного, но нужно знать на зубок мат.часть + постоянно практиковаться...))
                    Еще уточняющий вопрос есть по обработке файлов: используя потоки fstream читаем текстовый файл, в котором числа должны быть. Но вдруг встретилось не число, а например СЛОВО. В этом случае это проверка вернет 0:
                    ExpandedWrap disabled
                      if (f >> current)   // если успешно прочитано число из текст.файла

                    как получить значение, на котором сбойнуло?? Придется прокручивать файл в самое начало, потом считывать нужное кол-во раз норм.числа, и затем в стр.переменную считать ошибочное значение?? Или можно в разы проще и быстрее??
                      Позиция в файле при ошибке чтения не меняется. Можно просто читать дальше. Но есть нюанс, да: если поток находится в состоянии ошибки, её сначала нужно сбросить, иначе поток и дальше не будет ничего делать, а продолжать возвращать состояние ошибки. std::basic_ios<>::clear(), например.
                        Цитата Qraizer @
                        Позиция в файле при ошибке чтения не меняется. Можно просто читать дальше. Но есть нюанс, да: если поток находится в состоянии ошибки, её сначала нужно сбросить, иначе поток и дальше не будет ничего делать, а продолжать возвращать состояние ошибки. std::basic_ios<>::clear(), например.

                        понятно, спс.
                        я не знаю, это нюанс или я туплю, но есть такое, что, если читать файл так:
                        ExpandedWrap disabled
                          f >> intVal;

                        а потом "резко" перейти на
                        ExpandedWrap disabled
                          ch = f.get()
                        ;
                        то он не может продолжать читать посимвольно. А вот если поставить f.clear() между этими чтениями, то он норм. переключается на посимвольное чтение после числового.
                        Возможно я сильно туплю и нет такой проблемы в принципе) но мне показалось, что есть)

                        Добавлено
                        кажется, понял, как раз происходит сброс ошибки f.clear(), о чем ты писал выше...
                        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                        0 пользователей:


                        Рейтинг@Mail.ru
                        [ Script execution time: 0,0349 ]   [ 16 queries used ]   [ Generated: 29.03.24, 15:55 GMT ]