Работа с текстовым файлом в C++ для начинающих. Запись и чтение

С файлами можно работать в двух направлениях: или брать из них данные, или записывать в них данные. Эта статья о чтении из текстовых файлов строчек.
Простое чтение из текстовых файлов в языке С++ достаточно легко освоить. Используемый мной вариант один из возможных.
Для чтения данных из файла надо подключить заголовочный файл (директиву) fstream.h


Эта директива подключается и для того, чтобы можно было записать файл, и для того, чтобы можно было прочитать данные из файла.
  • Чтение из текстового файла строчек в переменные мало отличается от использования cin>>

Это наипростейшая программа, способная прочитать информацию из первой строки файла, находящегося в C:\\FromC\\myfile.txt. Для того, чтобы с файла что-то прочиталось, файл конечно должен существовать, а в нём должно быть что-нибудь, что можно прочитать, т. е. любой текст.
Как и в предшествующей этой теме, где в файл записывался текст: Работа с текстовым файлом (1), объявляется объект, который будет играть роль файла. Сейчас этот объект назван in. Этот объект мы информируем о файле, для чего вовнутрь круглых скобок, связанных с объектом in, пишем или название файла, или полный путь к файлу. В моём случае указан полный путь: "C:\\FromC\\myfile.txt". При прописывании пути, слеши должны быть двойными.
Чтобы запомнить что-то, нужно то, во что запоминать. Мы запоминаем считываемые значения в переменные. Поскольку в текстовом файле хранятся строки, то логично запоминать строки в переменные или объекты, умеющие работать со строками. В простейшем примитивном случае такой переменной может стать обычный массив символьного типа, такой массив в первом листинге и используется. Т. е. мы читаем из файла строку в массив. На самом деле большой разницы в подходе к считыванию данных из разных источников нет, будь то или клавиатура или файл, всё сводится к использованию операции >>, применяемой к объекту, выполняющему роль источника. Например, объект cin выполняет роль клавиатуры, а созданный во втором листинге объект in выполняет роль файла, все они оказываются источниками информации разного рода, а применяемая к ним операция >> выполняет роль передачи информации из них.

Использование объекта in, тип которого ifstream, в связке с операцией >> позволяет опознать данные из связанного с объектом in файла.
В случае работы с клавиатурой, мы как бы переносим нажатые клавиши в переменные:

В случае работы с файлом, мы как бы переносим данные из файла в переменные:

Принципиальной разницы в подходе нет. Различие только в типе, который может обозначать или клавиатуру, или файл, или что-то другое, где может храниться информация.
  • Операция >> обычно применяется для подбора значений, читается как "взять из потока"
Вся эта статья едва ли не повторение предшествующей темы: Работа с текстовым файлом (1). Различие только в направлении угловых скобок: в зависимости от надобности читать или записывать — направление угловых скобок разное. Обычно, это значит, что не всегда так может быть, но чтобы никого не путать, правильный программист для чтения будет использовать угловые скобки, смотрящие вправо, а для записи угловые скобки, смотрящие влево.
В немного обобщённом виде запись в файл может выглядеть вот так:

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

Если всё правильно сделано, то у вас должен был получиться файл, в который должен был записаться текст и потом записанный текст наоборот, должен был прочитаться из файла и запомниться в переменные.
Обнуление символьных массивов происходит путём приписывания в первый символ признака конца строки. Поскольку имя любого массива умеет неявно приводиться к указательной переменной, то можно делать так, как я показал, для символьных массивов. Весь массив таким образом не обнуляется, но строка как будто бы получается пустой.
В случае обработки строк, показанный во втором листинге код имеет очень серьёзный недостаток: ввод строк с пробелами не даёт нам ожидаемый эффект. Программа как будто бы глючит. В принципе, вы уже можете знать, как бороться с такой бедой, но не все знакомы с решением.
  • Для того, чтобы воспринимались пробелы в строковых значениях, не нужно использовать операцию >>
Нужно использовать метод getline. Есть две вариации getline: один getline является методом потоковых объектов, другой getline относится к std::string. В нашем случае используется потоковый объект, который помогает работать с файлом. Объект, используемый для чтения файла был нами назван in, поскольку этот объект потокового характера (если название типа содержит stream, то это обычно тип для потоковых объектов). Нужно использовать метод getline, который является частью in.

При использовании метода getline, который через точку дописывается к in, нужно этому методу сообщать строковую переменную, в которую запоминаем информацию, и длину той строковой переменной. Когда мы запоминали значения в переменные, введённые с клавиатуры, мы использовали объект cin и метод getline, и когда подбирали значения в переменные из файла — тоже использовали метод getline. В общем, нужно его использовать при сохранении в переменные значений, если значения строковые и содержат пробелы, которые нам нужны. Есть немножко другой метод, который тоже называется getline, он относится к строковым объектам, тип которых std::string, вот в такой getline нужно подавать имя объекта, который может выполнять роль или клавиатуры, или файла, или другого источника и имя строкового объекта, в который запоминается информация.
Чтобы никто не запутался, повторюсь. Я использую getline, который относиться к потоковым объектам.
Надеюсь, у меня получилось объяснить вам популярно, понятно и очень в доступной форме, как в общих чертах можно работать с текстовыми файлами. Если вы поняли эту тему, то сделали очередной шажок к своему профессионализму.
Как и в случае с открытием файла для записи, в случае открытия файла для чтения не обязательно вписывать имя файла в круглые скобки непосредственно при объявлении объекта, выполняющего роль файла. Можно отложить привязывание объекта к файлу. Чтобы лишнее не отвлекало, всю основную часть третьего листинга убираю, оставляю только то, о чём пытаюсь сказать:

28 комментариев на «“Работа с текстовым файлом в C++ для начинающих. Запись и чтение”»

  1. Aleksey ad:

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

    Автор сайта отвечает:
    Aleksey ad, спасибо за проявленное внимание)) Честно говоря я не верю, что сам сильно далеко смогу уйти. Я пока стараюсь избегать указателей, т.к. для начинающих они немного запутывают смыслОдно дело веселится, другое дело не давать лишнего. Любой помощи был бы рад, т.к. один в поле не воин, как ни крути icq 586-115-460 email daslex@yandex.ru

    http://juniordeveloperad.blogspot.com/2012/04/junior-c-deloper-hi.html Вот, смотри. Я не знаю твоей мотивации и откуда ты берёшь свои азы…К примеру, по ссылке выложены задания по первой части предмета объектно-ориентированное программирование одного ииз Вузов. Могу скинуть на мыло книжку, по которой учаться студенты (её, конечно, не хватает). Про указатели скажу одно — надо разбираться. Для меня они остаются не до конца разобранными, но пользуюсь. Начал их разбирать с си. Там намного больше они участвуют в жизнедеятельности прилаги, там вообще больше ориентированно на работу с памятью. А потом перешёл на с++ и здесь опять же указатели. Многие говорят, что в с# они будут не нужны…Но я всё равно стараюсь разобраться и использовать их по максимуму 🙂 всё приходит с опытом.Кстати, в java нету указателей) Да и работа с памятью облегчена)По поводу контактов — не против, но icq не пользую. скайп скину на почту.

    Автор сайта отвечает:
    как С не С++, так и С++ не C#. java тоже – это java. К теме изучения C++ это не относится. Скорее это плюсы и минусы языков, поводы для дискуссий на форумах. по поводу книжки. может кому-то это тоже интересно и лучше дать автора и название книги сюда, чем лично мне
     
    И еще по поводу вашей ссылки я постараюсь не спорить с вами ни тут ни там, просто скажу что думаю «Начинать надо с потяжелее» – лично я считаю совершенно по другомуСтрауструп писал, что чем больше вы знаете С, тем сложнее будет перейти на С++, используя преимущества C++ (не дословно). Вы держитесь противоположной идеологии и это полностью ваше право.

    http://alfoot.net/lucik_op.doc книга преподавателей беларуского профильного вуза

  2. Anonymous:

    Спасибо чувак. Очень интересно написанно, а главное понятно и то, что нужно.

  3. Anonymous:

    endl — новая строка со сбросом буфера памяти. /n -просто новая строка.

    Автор сайта отвечает:
    Спасибо. Но глазами большинства начинающих это уточнение скорее всего мало понятно.

    Перед выводом информация обычно накапливается в буфере памяти. Манипулятор endl одновременно с переходом на новую строку осуществляет сброс буфера вывода данных, не дожидаясь момента ,когда он заполнится.

    Автор сайта отвечает:
    Был случай, что я столкнулся с разным срабатыванием этих команд в одной и той же ситуации, но пример я такой не помню и привести не могу. Если файл открыт в текстовом режиме, то не имеет значения как закрывать строку. Если программа нестабильна и нужно вывести все что есть имеет смысл использовать endl, Если очистка потока (сброс буфера памяти) не требуется, достаточно использовать «n»Можно об этом много разглагольствовать, но без примеров все эти слова мало что значат

  4. аноним:

    Здравствуйте!
    А как считать инфу из файла, если я не знаю заранее сколько в нем строк?

    Автор сайта отвечает:
    http://ci-plus-plus-snachala.ru/?p=51

    Спасибо, но у меня кучу ошибок выдал, в основном: невозможно переконвертировать из char const в char, также не распознал функции getch и clrscr.

    Автор сайта отвечает:
    А какой у вас компилятор?
    В моем примере были ошибки, поэтому я его переделал. Проверил. Вроде работает. но getch и clrscr зависит от компилятора. Это мелочи интерфейса. Очистка экрана и задержка, чтобы окно сразу не закрывалось.

    у меня visual c++
    ага, помню еще с паскаля про clrscr, значит выкину ее, а вместо getch system ("pause") поставлю, если не путаю. а что делать с
    char и const char?
    Я тут из учебника переписала такую программу. Она компилируется, зато вообще не понятно как работает. У меня файл открывается и сразу же закрывается, несмотря на то, что я вставила system ("pause"). А в учебнике написано тоже считывает информацию из файла.

    Автор сайта отвечает:
    а что делать с
    char и const char?
    ==========
    как я написал, у меня была ошибка.
    char FName="C:\MyFile.txt"; //было так
    char *Fname="C:\MyFile.txt" //уже там так. Благодаря вам исправлено. Посмотрите просто снова

    видимо для ms visual c++ ваша программа не годится(все ошибки в этих двух строчках const N=256; //Константный размер строки
    char *Fname="C:\text.txt";):
    c:\documents and settings\мария\рабочий стол\апка\9.файлы\9.файлы.cpp(8): error C4430: missing type specifier — int assumed. Note: C++ does not support default-int
    error C2065: ‘"C’ : undeclared identifier
    error C2143: syntax error : missing ‘;’ before ‘:’
    error C2059: syntax error : ‘:’
    error C2017: illegal escape sequence
    error C2143: syntax error : missing ‘;’ before ‘.’
    error C4430: missing type specifier — int assumed. Note: C++ does not support default-int
    error C2065: ‘FName’ : undeclared identifier

    Автор сайта отвечает:
    если вы мой пример поймете (на что я надеюсь), то когда будете лабораторные сдавать или что-то сами писать, нужно проверять на ошибки

    я эти моменты специально пропускал, чтобы код легче воспринимался, но игнорировать возможные ошибки плохо.
    =================
    а в визуал Studio задержек можно не ставить Ctrl+F5. Так попробуйте компилировать. А очистка экрана system(“CLS”); (у меня в примерах встречается иногда)

    да это-то понятно. не понятно откуда они этот файл берут! нигде путь не указан.

    Автор сайта отвечает:
    сейчас я для VisualStudio сделаю. Вы подождите чуть-чуть 🙂
     
    Всё. Для Visual Studio готово. Можете смотреть.

    а in они берут из

    http://ci-plus-plus-snachala.ru/?p=51
    тут теперь есть пример для Visual Studio

    У меня ничего не считывает.
    А паузы создают, потому что прога должна работать сама собой, прямым открытием, а не через компилятор. Не у всех есть эти компиляторы. Ну это я так просто.
     
    у меня тоже не считывает и этот не считывает. а у вас ваш пример считывает? простите за тавтологию)))

    Автор сайта отвечает:
    с чувством юмора )
     
    да. у меня VisualStudio 2005. там пример, который описывал я работает. (мы немного не в той теме комментируем, поэтому может я об одном, а вы о другом). Еще может вы пишете на русском, а вам отдает абракадабру.
    у меня ваш пример из книги тоже ничего не считывает

    вот я наконец-то пример нашла который все считывает. может кому-то пригодится

    Автор сайта отвечает:
    да, если бы еще не обрезалось все так. то было бы хорошо. Наверное не обратили внимание, что в комментариях код убивается.

  5. Ваня:

    Объясните, пожалуйста, значение *"" в строке:
    Спасибо.

    Автор сайта отвечает:
    честно не помню. Но попробую объяснить.

    Чуть выше вся строка была забита символом "" (пустота). Вот если в строке, считываемой из файла будет, например 3 или 4 символа, то это слишком мало и чтобы не проходить по всей строке в 255 символов, можно сделать досрочный выход из цикла for встретив символ "".

    Вроде так.

    Ясно, я вроде разобрался. Большое спасибо за ответ.

  6. Aлександра:

    насчёт этой строки, * это ведь указатель?
    При компиляции мне выдаёт такую ошибку "Possibly incorrect assignment"
    Через Turbo C++
     
    Из-за этого, как я думаю, из файла не выводится ничегоВ файл записывается, и всё.

    Автор сайта отвечает:
    Про вывод файла здесь
    http://ci-plus-plus-snachala.ru/?p=51

    *"" попробуйте заменить везде на NULL

  7. Aлександра:

    Из-за этого, как я думаю, из файла не выводится ничегоВ файл записывается, и всё.

  8. Аноним:

    Здравствуйте! У меня вот какая проблема. Начала пробовать работу с файлами уже написала простую программку, решила попробовать что-то посложнее, но передо мной встала проблема, что выдает ошибку на первой же строке не воспринимает #include и, также, ни в какую не воспринимает строку using namespace std; Написано без ошибок, раз десять проверяла, копировала эти строки из другой, работающей программы, все равно выдает ту же ошибку. Почему это происходит и что можно с этим сделать?

    Автор сайта отвечает:
    от среды разработки зависит
    в Borland C++ 3.1
    не надо писать using namespace std


    В Visual Studio

    можно использовать using namecpace std

    iostream,fstream или другие директивы, все они с подобными правилами.

  9. Максим:

    А не подскажите как прописать универсальный адрес для папки AppData?

  10. ktanov@bk.ru:

    Спасибо Вам Всем, особенно АДМИНУ!!! Мне еще до вас далеко, но я учусь!

  11. Наталья:

    Автор, а Вы, случаем, не планируете сделать статью о выводе на печать? Было бы не лишнее, я думаю,учусь по Вашему блогу, а вот появилась лабораторная по теме вывода на печать из файла, а такой темы у Вас и нету, печально 🙁
    P.S. или я слепая, ткните носом тогда 😕 😳

    Автор сайта отвечает:
    Нет, вы Не слепая. Этой темы и правда нет. Есть и другие полезные темы, которых у меня нет.
    Если я начну делать эту статью сейчас, то не думаю, что успею к срокам сдачи вашей работы. И не факт, что вообще смогу ее описать, что смогу описать грамотно, хорошо и так, чтобы понятно всем было.

    Сейчас у меня все время уходит не на блог и не на изучение С++, поэтому шансов, что эта тема появится почти нет
     
    Вот здесь немного про печать написано (я не пробовал, но буду надеяться окажется полезным)
    http://forum.developing.ru/showthread.php/2843-%D0%9F%D0%B5%D1%87%D0%B0%D1%82%D1%8C-%D0%BD%D0%B0-%D0%BB%D0%B0%D0%B7%D0%B5%D1%80%D0%BD%D0%BE%D0%BC-%D0%BF%D1%80%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B5-%D0%B8%D0%B7-DOS-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F-%D0%BD%D0%B0-C

    Если принтер подключен к LPT-порту, то текст можно выводить как в обычный текстовый файл, только имя файла нужно указать «LPT1».
    Печать начинается сразу после получения символа новой страницы (‘\f’) или после закрытия файлового потока.

  12. Sergio:

    Не сразу понял, почему у меня последний пример из статьи ведёт себя неадекватно, но, поковырявшись, всё же разобрался. Итак, по-порядку (в скобках буду указывать номера строк):
    (1,2) Зачем дважды подключать библиотеку fstream.h? 🙄
    (12, 13) Грубая опечатка! При выводе информации видим только последнюю введённую строку, а дальше сплошной мусор… Подправьте:

    (18, 19, 20, 40, 48) Очень часто забываете слэши при переходе на новую строку…

    Если всё это подправить, то работает прекрасно. 😀
    P.S. В каком-то смысле проверка ваших примеров есть отличное практическое упражнение))

  13. Gen:

    В CODE::BLOCK не работает! Если написать

    и

    и переменную int i объявлять в каждом цикле или не циклах,а в начале программы,тогда работает.
    P.S. В каком-то смысле проверка ваших примеров есть отличное практическое упражнение

    Автор сайта отвечает:
    Разумеется там не должно работать то, что написано в динозаврах. (В borland C++ 3.1).
    Работа с переменными, объявленными в циклах, как в примере статьи (for int i=) различна для разных компиляторов. Если в компиляторе, используемом в CodeBlocks такая переменная умирает после завершения работы цикла, то в компиляторе, используемом в Borland C++ 3.1 такая переменная не умирает после завершения работы цикла. И поэтому если объявлять переменную в каждом цикле в Borland C++ 3.1, то будет ошибка типа: “одна переменная объявлена много раз”.
    Я использовал Borland C++ 3.1 потому как мне он был удобен, привычен после Turbo Pascal и мал размером.
    Но, в любом случае, правильнее использовать новые компиляторы и современные IDE

  14. Sergio:

    Добрый день! Интересует меня следующий вопрос:
    При чтении из файла разве не могут возникнуть никакие ошибки? Возвращает ли ifstream какое-нибудь значение при неудачной операции чтения?

    Автор сайта отвечает:
    ifstream — это не функция, это класс. Классы сами по себе ничего не возвращают.

    У классов могут быть объекты.
    У объектов класса могут быть функции (методы класса). Такие функции возвращают значения.

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

    У класса ifstream есть методы, которые возвращают значения в том числе и в зависимости от успешного или безуспешного выполнения. Т.е., объект данного класса может возвращать признак ошибки.

    Чтобы это понять лучше имеет смысл прочитать про классы.

    Спасибо за ответ!

  15. Нойон:

    Здравствуйте!
    У меня среда разработки RAD Studio XE3
    и тривиальная задача «открыть текстовый файл и по образцу удалить текст, далее сохранить, что осталось»
    пытаюсь написать на С++ и Delphi, пока не получается
    может сталкивались, ситуация распространенная.
    Подскажите хотя-бы направление.
    В идеале нужно обработать сотни файлов в оной папке.
    Спасибо!

  16. Нойон:

    Ещё раз спасибо, буду продолжать.

  17. eva:

    Разобралась!! Спасибо ОГРОМНОЕ!!

  18. desannn:

    Люди серьезно?

    Может я сейчас скажу какую-нибудь глупость но:

    1.Неужели нельзя использовать string;

    2.Неужели нельзя искать по содержимому строки?

     

  19. desannn:

    добавление к предыдущему комменту а если быть точным к его части 2. * а не по номеру строки.

  20. desannn:

    Такой вопрос :

    пишу значит программу для добавления логинов и паролей в файл используя fsteam и вроде программа выполняется без ошибок, но в файл ничего не добавляет работаю с visual studio 2013 вот код:

    внимание вопрос:

    в чем проблема?

  21. Влад Крокозябра:

    Как сделать поиск по файлу введённых человеком слов?

  22. Игорь:

    такой вопрос, вы задали имена объектов out и  in, так каждый должен задавать или все таки их можно называть как хочешь?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Поиск

 
     

Случайная книга в электронном формате

https://www.litres.ru/mihail-flenov/bibliya-c-4575419/?lfrom=15589587
Яндекс.Метрика