Улучшение сложности пространства при чтении из файла - PullRequest
1 голос
/ 01 августа 2011

У меня есть произвольно длинная строка целых чисел (или значений с плавающей запятой), разделенных запятыми в файле:

1,2,3,4,5,6,7,8,2,3,4,5,6,7,8,9,3,...  (can go upto >100 MB)

Теперь я должен прочитать эти значения и сохранить их в массиве.

Моя текущая реализация выглядит так:

 float* read_line(int dimension)
   {
     float *values = new float[dimension*dimension]; // a line will have dimension^2 values
     std::string line;
     char *token = NULL, *buffer = NULL, *tmp = NULL;
     int count = 0;

     getline(file, line);
     buffer = new char[line.length() + 1];
     strcpy(buffer, line.c_str());
     for( token = strtok(buffer, ","); token != NULL; token = strtok(NULL, ","), count++ )
       {
         values[count] = strtod(token, &tmp);
       }
     delete buffer;
     return values;
   }

Мне не нравится эта реализация, потому что:

  • Используя ifstream, весь файл загружается в память, и затем клонируется в float []
  • Существует ненужное дублирование (преобразование из std::string в const char*)

Как оптимизировать использование памяти?

Спасибо!

Ответы [ 3 ]

4 голосов
/ 01 августа 2011

Как то так?

float val;
while (file >> val)
{
  values[count++] = val;
  char comma;
  file >> comma; // skip comma
}
1 голос
/ 01 августа 2011

Использование буст-токенизатора и istreambuf_iterator:

std::vector<float> test; //Optionally call reserve to avoid frequent memory reallocation
boost::tokenizer<boost::char_separator<char>, std::istreambuf_iterator<char> > tokens(std::istreambuf_iterator<char> (in), std::istreambuf_iterator<char>(), boost::char_separator<char>(","));
//Replace this lambda by your favourite conversion function.
std::transform(tokens.begin(), tokens.end(), std::back_inserter(test), [](std::basic_string<char> s) { return atof(s.c_str()); } );

edit: test - это то, что я использую для values, за исключением того, что это std::vector вместо массивов, что обычно является лучшим выбором.

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

0 голосов
/ 02 августа 2011

Я хотел попробовать что-то, основываясь на предложении osgx использовать scanf:

freopen("testcases.in", "r", stdin);
while( count < total_values)
       {
         scanf("%f,",&values[count]);
         count++;
       }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...