Как мне создать массив объектов ifstream и как заполнить этот массив пронумерованными текстовыми файлами?

У меня есть куча текстовых файлов в каталоге, и каждый текстовый файл называется «info1.txt», «info2.txt» и так далее. Как бы мне открыть все текстовые файлы в массиве объектов ifstream без жесткого кодирования имен всех моих текстовых файлов? Я знаю, что следующий код не работает, но я думаю, что он передает идею того, что я хочу сделать, если он сработает:

ifstream myFiles[5];
for(int i = 0; i < 5; i++){
    myFiles[i].open("info" + i + ".txt");
}

Я знаю, что решение, вероятно, очень простое, но после долгих исследований, проб и ошибок я так и не понял его. Спасибо!


person ahabos    schedule 19.10.2012    source источник
comment
вы можете искать все файлы, находящиеся внутри определенной папки, брать там имя и использовать его для создания массива ifstream   -  person Adrian Herea    schedule 19.10.2012


Ответы (5)


Проблема, я думаю, в части динамического создания имени файла.

Одним из простых решений является использование для этого std::ostringstream:

ifstream myFiles[5];
for(int i = 0; i < 5; i++){
    ostringstream filename;
    filename << "info" << i ".txt";
    myFiles[i].open(filename.str());
}

Если ваша библиотека устарела, чтобы принимать аргументы std::string в вызове open, используйте

    myFiles[i].open(filename.str().c_str());
person Some programmer dude    schedule 19.10.2012

Для создания имен файлов я бы использовал std::ostringstream и operator<<.

Если вы хотите использовать контейнерный класс, такой как std::vector (например, потому что во время компиляции вы не знаете, насколько большим будет массив ifstream), поскольку std::ifstream не копируется, вы не можете использовать vector<ifstream>, но вы можете использовать vector<shared_ptr<ifstream>> или vector<unique_ptr<ifstream>>; например.:

vector<shared_ptr<ifstream>> myFiles;
for (int i = 0; i < count; i++)
{
    ostringstream filename;
    filename << "info" << i << ".txt";
    myFiles.push_back( make_shared<ifstream>( filename.str() ) );        
}

С unique_ptr (и семантикой перемещения С++ 11):

vector<unique_ptr<ifstream>> myFiles;
for (int i = 0; i < count; i++)
{
    ostringstream filename;
    filename << "info" << i << ".txt";
    unique_ptr<ifstream> file( new ifstream(filename.str()) );
    myFiles.push_back( move(file) );
}

unqiue_ptr более эффективен, чем shared_ptr, так как unique_ptr — это просто перемещаемый указатель, он не подсчитывает ссылки (поэтому меньше накладных расходов, чем shared_ptr). Таким образом, в С++ 11 вы можете предпочесть unique_ptr, если ifstream не используются совместно за пределами контейнера vector.

person Mr.C64    schedule 19.10.2012

Ваша идея должна работать с небольшим изменением:

myFiles[i].open((std::string("info") + itoa(i) + ".txt").c_str());
             // ^^^^^^^^^^^           ^^^^

Также обратите внимание, что вы не можете использовать std::vector, потому что ifstream не является копируемым объектом. Так что продолжайте использовать массив.

person iammilind    schedule 19.10.2012
comment
Он мог использовать vector<unique_ptr<ifstream>> или vector<shared_ptr<ifstream>>. - person Mr.C64; 19.10.2012
comment
Спасибо за это! Есть ли элемент #include, который мне нужен для использования itoa? У меня есть несколько вещей, но когда я компилирую, я получаю сообщение об ошибке, что itoa не объявлено в области. - person ahabos; 19.10.2012
comment
Массив будет работать только в том случае, если количество файлов известно во время компиляции. Если он меняется во время выполнения, ему понадобится динамическая коллекция. vector‹shared_ptr‹ifstream› › будет работать (или unique_ptr, если доступно) - person CashCow; 19.10.2012

Я обычно использую std::stringstream:

{
  std::stringstream filename;
  filename << "info" << i << ".txt" << std::ends;
  myFiles[i].open(filename.str().c_str());
}
person Lucian    schedule 19.10.2012

У вас может быть массив объектов ifstream, но если вам нужна динамическая длина, то вы не можете сделать это таким образом, и std::vector<ifstream> не сработает.

Итак, вам понадобятся указатели. std::vector<ifstream*> будет работать, но вы можете использовать shared_ptr, поэтому std::vector<shared_ptr<ifstream> > будет работать. Если у вас есть unique_ptr, вы можете использовать его вместо shared_ptr.

Затем каждый элемент должен быть создан с помощью new.

Вам также нужно будет правильно создать строку, для этого вы можете использовать boost::format или ostringstream или даже старомодную sprintf.

Кстати, я бы поискал в библиотеке файловой системы boost, чтобы узнать, есть ли у них более динамичный ifstream, который может успешно работать в вашем векторе без беспорядка shared_ptr.

person CashCow    schedule 19.10.2012