Перейти к содержанию

C++ Stl Посимвольное Считывание Многострочного Текстового Файла В Вектор Строк


Рекомендуемые сообщения

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

 

Нужно знать

 

 

Я приведу пример С++ для посимвольного считывания текста из многострочного тестового файла, с запоминанием каждого абзаца внутри вектора. Код проверен в MinGW

#include <fstream>  //Для файловых потоков#include <iostream> #include <string>   //Для контейнера string#include <vector>  //Для контейнера vector#include <iterator> //Для вывода элементов вектора  на экран с помощью алгоритма copyusing namespace std;int main(){  int ch=0;  //Это переменная, в которую нужно считывать символы  string s;  //Это строка, она в примере будет абзацем  vector<string> v; //Вектор строк   const char *FName="M:\test.txt";  //Путь к файлу. У вас свой. Файл должен существовать.  int i;//Считаем текст с форматированием  ifstream in(FName);     //открыли для чтения  файл   while((ch = in.get()) != EOF) {   //объяснение ниже        if (char(ch)!='n') s=s+char(ch);  //Считываем символ из файла и сразу проверяем его на признак переноса строки.         else {                 v.push_back(s); //Если текущий символ перенос, то записываем строку в вектор                 s.clear(); //Очищаем строку        }    }    v.push_back(s); //Дописываем последнюю строку в вектор.    in.close(); //Закрываем файл  //cout<<v.at(0)<<"nn";  //Можете посмотреть первую строку, чтобы убедиться, что абзацы разделились.   copy(v.begin(),v.end(),std::ostream_iterator<string>(cout,"nn"));  //Вывожу вектор на экран}

Такой вот пример задачки: "Как считать многострочный текстовый файл в вектор строк" Так как могут быть совсем еще только начавшие учить программирование С++, то разберемся подробно, что получается.

 

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

while((ch = in.get()) != EOF) //Считывать каждый символ в поток in
ch=in.get()  //Вот оно это считывание. Для тех, кто знаком с методом get() объекта cin,              //эта запись может быть до боли знакома. Ведь, чтобы считать с клавиатуры символ часто используется             //ch=cin.get(). Похоже очень

Объект cin – это тоже потоковый объект. Ведь из определения

 

  • cin– объект класса ostream, соответствующий стандартному вводу. В общем случае он позволяет вводить данные c клавиатуры;

 

Объект cin = поток

Объект in = поток

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

EOF - это символ конца файла. В каждом файле такой символ есть, вот после записи данных в ch, я сразу проверяю этот ch на то, что он НЕ является концом файла. Ведь если он не является, то надо читать символы дальше.

ch = in.get()) != EOF

это получается как

ch=in.get(); //Запомнили символ в памятиif (ch!=EOF) //Проверили на то, что символ не равен символу конца файла.

Так мы добрались до внутри цикла. Внутри идет сборка строки, проверка ch на то, что он не является символом переноса строки и, если он является переносом, то собранная строка записывается в вектор. После записи строки s в вектор, строка обязательно очищается. Ведь если не очистить строку, то эта строка продолжит собираться с уже накопленными в ней символами. Ну и после выполнения цикла дописывается последняя строка в вектор строк.

 

Надеюсь написал настолько подробно, что вопросов будет меньше чем могло бы быть.

 

Какую ошибку обычно делают. Часто делают такую ошибку, что проверяют признак конца файла методом потока

while(!in.eof()){  //Проверка не символа, а потока  ch=in.get();  ...}

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

 

Источник - http://nomerateka.ru

Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.