Как считать числа из ASCII-файла (C++)

Из Википедии:

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

18
задан Peter Mortensen 28 February 2012 в 21:50
поделиться

4 ответа

Поскольку это помечено как C ++, наиболее очевидным способом было бы использование потоков. В голове у меня может получиться что-то вроде этого:

std::vector<float> readFile(std::istream& is)
{
  char chdummy;
  is >> std::ws >> chdummy >> std::ws; 
  if(!is || chdummy != '*') error();
  std::string strdummy;
  std::getline(is,strdummy,':');
  if(!is || strdummy != "SZA") error();

  std::vector<float> result;
  for(;;)
  {
    float number;
    if( !is>>number ) break;
    result.push_back(number);
  }
  if( !is.eof() ) error();

  return result;
}

Почему float , BTW? Обычно двойной намного лучше.

Отредактируйте , так как возник вопрос, является ли возвращение копии вектора хорошей идеей:

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

(Также обратите внимание, что C ++ 1x с поддержкой rvalue, который, надеюсь, скоро будет доступен с помощью ближайшего к вам компилятора, сделает это обсуждение спорным, поскольку это предотвратит копирование вектора после возврата из функции.)

11
ответ дан 30 November 2019 в 07:44
поделиться

Библиотека String Toolkit Library (Strtk) предлагает следующее решение вашей проблемы:

#include <iostream>
#include <string>
#include <deque>
#include <iterator>

#include "strtk.hpp"

int main()
{
    std::deque<float> flist;
    strtk::for_each_line("file.txt",
                         [&flist](const std::string& line)
                         { strtk::parse(line," ",flist); }
                         );
    std::copy(flist.begin(),flist.end(),
              std::ostream_iterator<float>(std::cout,"\t"));
    return 0;
}

Дополнительные примеры можно найти в C ++ String Toolkit (StrTk) Tokenizer .

18
ответ дан 30 November 2019 в 07:44
поделиться

Простое решение с использованием алгоритмов STL:

#include <vector>
#include <iostream>
#include <string>
#include <iterator>

struct data
{
   float first; // in case it is required, and assuming it is 
                // different from the rest
   std::vector<float> values;
};

data read_file( std::istream& in )
{
   std::string tmp;
   data d;
   in >> tmp >> tmp >> d.first;
   if ( !in ) throw std::runtime_error( "Failed to parse line" );

   std::copy( std::istream_iterator<float>( in ), std::istream_iterator<float>(),
         std::back_inserter<float>(d.values) );

   return data;
}

Если вам действительно нужно использовать массив, вы должны сначала выделить его (динамически или статически, если вы знаете размер), а затем вы можете использовать тот же алгоритм копирования

// parsing the first line would be equivalent
float data[128]; // assuming 128 elements known at compile time
std::copy( std::istream_iterator<float>(is), std::istream_iterator<float>(), 
      data );

Но я бы рекомендовал использовать std :: vector даже в этом случае, если вам нужно передать данные в функцию, которая принимает массив, вы всегда можете передать его как указатель на первый элемент:

void f( float* data, int size );
int main()
{
   std::vector<float> v; // and populate
   f( &v[0], v.size() ); // memory is guaranteed to be contiguous
}
2
ответ дан 30 November 2019 в 07:44
поделиться

Я бы сделал что-то вроде этого:

std::ifstream input("input.txt");
std::vector<float> floats;
std::string header;
std::getline(input, header); // read in the "* SZA: 10.00" line
if(header_is_correct(header)) {
    float value;
    // while we could successfully read in a float from the file...
    while(input >> value) {
        // store it in the vector.
        floats.push_back(value);
    }
}

ПРИМЕЧАНИЕ: header_is_correct (header) - это просто пример, вам нужно будет выполнить проверку ошибок для этой первой строки вручную там.

2
ответ дан 30 November 2019 в 07:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: