Не считывает файл c

Обновлено: 06.07.2024

Хедер fstream предоставляет функционал для считывания данных из файла и для записи в файл. В целом он очень похож на хедер iostream , который работает с консолью, поскольку консоль это тоже файл. Поэтому все основные операции такие же, за мелкими отличиями, как в предыдущей теме по iostream.

Наиболее частые операции следующее:

    1. Методы проверки открыт ли файл is_open() и достигнут ли конец файла eof()
      1. Настройка форматированного вывода для >> с помощью width() и precision()
      1. Операции позиционирования tellg(), tellp() и seekg(), seekp()

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

      Класс ifstream

      Открытие файла в конструкторе выглядит так:

      ifstream file ( "d:\\1\\файл.txt" ) ; // открываем файл в конструкторе

      Так мы просим открыть файл txt с именем файл.txt, который лежит в папке с названием 1, а папка находится на диске d.

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

      Так все отработает нормально и файл откроется:

      библиотека fstream, работа с файлами в с++, программирование для начинающих

      Второй вариант проверки с использованием метода is_open() :

      Метод is_open() вернет 1, если файл найден и успешно открыт. Иначе вернет 0 и сработает код прописанный в блоке else .

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

      Оператор считывания >>

      Так же как и в iostream считывание можно организовать оператором >> , который указывает в какую переменную будет произведено считывание:

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

      Кстати этот оператор достаточно удобен, если стоит задача разделить файл на слова:

      Методы getline() и get()

      Считывание целой строки до перевода каретки производится так же как и в iostream методом getline(). Причем рекомендуется использовать его переопределеную версию в виде функции, если считывается строка типа string:

      Если же читать нужно в массив символов char[], то либо get() либо getline() именно как методы:

      Принцип в общем тот же, что и в аналогах из iostream: Указывается в параметрах буфер (переменная, куда будет производиться чтение), или точнее указатель на блок памяти (если переменная объявлена статически: char buffer[255] к примеру, то пишется в параметры &buffer), указывается максимальное количество считываемого (в примере это n), дабы не произошло переполнение и выход за пределы буфера и по необходимости символ-разделитель, до которого будет считка (в примере это пробел). Надеюсь я не больно наступлю на хобот фанатикам Си, если сажу что эти две функции на 99% взаимозаменяемы, и на 95% могут быть заменены методом read() .

      Метод read()

      Похож на предыдущий пример?

      Метод close()

      Метод eof()

      Проверяет не достигнут ли конец файла. Т.е. можно ли из него продолжать чтение. Выше пример с считкой слов оператором >> как раз использует такую проверку.

      Метод seekg()

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

      CityCat4

      Не надо использовать эту [beep] конструкцию while(!feof())
      От нее только проблемы. Используйте fscanf() в цикле, пока он не вернет EOF.

      Да, я знаю, что в примерах так - я сам когда-то писал по таким же примерам и потом долго матерился, не понимая, почему не работает.

      Насколько мне известно, fscanf не возвращает EOF. Возвращает 0.

      CityCat4

      On success, these functions return the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure.

      The value EOF is returned if the end of input is reached before either the first successful conversion
      or a matching failure occurs. EOF is also returned if a read error occurs, in which case the error
      indicator for the stream (see ferror(3)) is set, and errno is set to indicate the error.

      Можно для гарантии проверять на возврат нуля, конечно же. Мне вот все эти танцы с потоковым чтением видятся осмысленными только для файлов гигантского размера типа сквидовых логов. Файлы осмысленного размера проще читать через read (ну или read-sscanf - для ленивых)

      feof возвращает true, когда мы попытались прочитать и не смогли, потому что каретка ударилась в конец файла. А не когда каретка аккуратно припарковалась в конце файла — и уж тем более не когда она отделена от конца пробелами.

      Лучше прочитайте про scanf…

      On success, the function returns the number of items of the argument list successfully filled. This count can match the expected number of items or be less (even zero) due to a matching failure, a reading error, or the reach of the end-of-file.

      BacCM

      1. Стоит проверять что возвращает функция чтения fscanf.
      Она явно не смогла прочитать число из потока.
      У тебя в файле после последней единицы что-то есть типа возврата строки, пробела или чего-то подобного.

      2. Уже к чистоте кода держите переменные ближе к месту использования. temp сразу перед fscanf и ещё и чем нибудь инициализировать. Тогда как минимум в подобных случаях будет не последнее значение, а "маркер"

      До этого при вводе-выводе данных мы работали со стандартными потоками — клавиатурой и монитором. Теперь рассмотрим, как в языке C реализовано получение данных из файлов и запись их туда. Перед тем как выполнять эти операции, надо открыть файл и получить доступ к нему.

      В языке программирования C указатель на файл имеет тип FILE и его объявление выглядит так:

      С другой стороны, функция fopen() открывает файл по указанному в качестве первого аргумента адресу в режиме чтения ("r"), записи ("w") или добавления ("a") и возвращает в программу указатель на него. Поэтому процесс открытия файла и подключения его к программе выглядит примерно так:

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

      При чтении или записи данных в файл обращение к нему осуществляется посредством файлового указателя (в данном случае, myfile).

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

      Объявление функции fopen() содержится в заголовочном файле stdio.h, поэтому требуется его подключение. Также в stdio.h объявлен тип-структура FILE.

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

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

      Чтение из текстового файла и запись в него

      fscanf()

      Функция fscanf() аналогична по смыслу функции scanf() , но в отличии от нее осуществляет форматированный ввод из файла, а не стандартного потока ввода. Функция fscanf() принимает параметры: файловый указатель, строку формата, адреса областей памяти для записи данных:

      Возвращает количество удачно считанных данных или EOF. Пробелы, символы перехода на новую строку учитываются как разделители данных.

      Допустим, у нас есть файл содержащий такое описание объектов:

      Тогда, чтобы считать эти данные, мы можем написать такую программу:

      В данном случае объявляется структура и массив структур. Каждая строка из файла соответствует одному элементу массива; элемент массива представляет собой структуру, содержащую строковое и два числовых поля. За одну итерацию цикл считывает одну строку. Когда встречается конец файла fscanf() возвращает значение EOF и цикл завершается.

      fgets()

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

      Такой вызов функции прочитает из файла, связанного с указателем myfile, одну строку текста полностью, если ее длина меньше 50 символов с учетом символа '\n', который функция также сохранит в массиве. Последним (50-ым) элементом массива str будет символ '\0', добавленный fgets() . Если строка окажется длиннее, то функция прочитает 49 символов и в конце запишет '\0'. В таком случае '\n' в считанной строке содержаться не будет.

      В этой программе в отличие от предыдущей данные считываются строка за строкой в массив arr. Когда считывается следующая строка, предыдущая теряется. Функция fgets() возвращает NULL в случае, если не может прочитать следующую строку.

      getc() или fgetc()

      Функция getc() или fgetc() (работает и то и другое) позволяет получить из файла очередной один символ.

      Приведенный в качестве примера код выводит данные из файла на экран.

      Запись в текстовый файл

      Также как и ввод, вывод в файл может быть различным.

      • Форматированный вывод. Функция fprintf ( файловый_указатель, строка_формата, переменные ) .
      • Посточный вывод. Функция fputs ( строка, файловый_указатель ) .
      • Посимвольный вывод. Функция fputc() или putc( символ, файловый_указатель ) .

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

      Запись в каждую строку файла полей одной структуры:

      Построчный вывод в файл ( fputs() , в отличие от puts() сама не помещает в конце строки '\n'):

      Пример посимвольного вывода:

      Чтение из двоичного файла и запись в него

      С файлом можно работать не как с последовательностью символов, а как с последовательностью байтов. В принципе, с нетекстовыми файлами работать по-другому не возможно. Однако так можно читать и писать и в текстовые файлы. Преимущество такого способа доступа к файлу заключается в скорости чтения-записи: за одно обращение можно считать/записать существенный блок информации.

      При открытии файла для двоичного доступа, вторым параметром функции fopen() является строка "rb" или "wb".

      Тема о работе с двоичными файлами достаточно сложная, для ее изучения требуется отдельный урок. Здесь будут отмечены только особенности функций чтения-записи в файл, который рассматривается как поток байтов.

      Функции fread() и fwrite() принимают в качестве параметров:

      1. адрес области памяти, куда данные записываются или откуда считываются,
      2. размер одного данного какого-либо типа,
      3. количество считываемых данных указанного размера,
      4. файловый указатель.

      Эти функции возвращают количество успешно прочитанных или записанных данных. Т.е. можно "заказать" считывание 50 элементов данных, а получить только 10. Ошибки при этом не возникнет.

      Пример использования функций fread() и fwrite() :

      Здесь осуществляется попытка чтения из первого файла 50-ти символов. В n сохраняется количество реально считанных символов. Значение n может быть равно 50 или меньше. Данные помещаются в строку. То же самое происходит со вторым файлом. Далее первая строка присоединяется ко второй, и данные сбрасываются в третий файл.

      БлогNot. Лекции по C/C++: работа с файлами (fstream)

      Лекции по C/C++: работа с файлами (fstream)

      Механизм ввода-вывода, разработанный для обычного языка С, не соответствует общепринятому сегодня стилю объектно-ориентированного программирования, кроме того, он активно использует операции с указателями, считающиеся потенциально небезопасными в современных защищённых средах выполнения кода. Альтернативой при разработке прикладных приложений является механизм стандартных классов ввода-вывода, предоставляемый стандартом языка C++.

      Открытие файлов

      Наиболее часто применяются классы ifstream для чтения, ofstream для записи и fstream для модификации файлов.

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

      Ниже приведены возможные значения флагов и их назначение.

      Режим Назначение
      in Открыть для ввода (выбирается по умолчанию для ifstream)
      out Открыть для вывода (выбирается по умолчанию для ofstream)
      binary Открыть файл в бинарном виде
      aрр Присоединять данные; запись в конец файла
      ate Установить файловый указатель на конец файла
      trunc Уничтожить содержимое, если файл существует (выбирается по умолчанию, если флаг out указан, а флаги ate и арр — нет)

      Например, чтобы открыть файл с именем test.txt для чтения данных в бинарном виде, следует написать:

      Оператор логического ИЛИ ( | ) позволяет составить режим с любым сочетанием флагов. Так, чтобы, открывая файл по записи, случайно не затереть существующий файл с тем же именем, надо использовать следующую форму:

      Предполагается, что к проекту подключён соответствующий заголовочный файл:

      Для проверки того удалось ли открыть файл, можно применять конструкцию

      Операторы включения и извлечения

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

      Можно также записывать текстовую строку по частям:

      Оператор endl завершает ввод строки символом "возврат каретки":

      С помощью оператора включения несложно записывать в файл значения переменных или элементов массива:

      В результате выполнения кода образуется три строки текстового файла Temp.txt :

      Обратите внимание, что числовые значения записываются в файл в виде текстовых строк, а не двоичных значений.

      Оператор извлечения ( >> )производит обратные действия. Казалось бы, чтобы извлечь символы из файла Temp.txt , записанного ранее, нужно написать код наподобие следующего:

      Однако оператор извлечения остановится на первом попавшемся разделителе (символе пробела, табуляции или новой строки). Таким образом, при разборе предложения "Текстовый массив содержит переменные" только слово "Текстовый" запишется в массив buff , пробел игнорируется, а слово "массив" станет значением целой переменной vx и исполнение кода "пойдет вразнос" с неминуемым нарушением структуры данных. Далее, при обсуждении класса ifstream , будет показано, как правильно организовать чтение файла из предыдущего примера.

      Класс ifstream: чтение файлов

      Как следует из расшифровки названия, класс ifstream предназначен для ввода файлового потока. Далее перечислены основные методы класса. Большая часть из них унаследована от класса istream и перегружена с расширением родительской функциональности. К примеру, функция get , в зависимости от параметра вызова, способна считывать не только одиночный символ, но и символьный блок.

      Метод Описание
      open Открывает файл для чтения
      get Читает один или более символов из файла
      getline Читает символьную строку из текстового файла или данные из бинарного файла до определенного ограничителя
      read Считывает заданное число байт из файла в память
      eof Возвращает ненулевое значение (true), когда указатель потока достигает конца файла
      peek Выдает очередной символ потока, но не выбирает его
      seekg Перемещает указатель позиционирования файла в заданное положение
      tellg Возвращает текущее значение указателя позиционирования файла
      close Закрывает файл

      Теперь понятно, как нужно модифицировать предыдущий пример, чтобы использование оператора извлечения данных давало ожидаемый результат:

      Метод getline прочитает первую строку файла до конца, а оператор >> присвоит значения переменным.

      Следующий пример показывает добавление данных в текстовый файл с последующим чтением всего файла. Цикл while (1) используется вместо while(!file2.eof()) по причинам, которые обсуждались в предыдущей лекции.

      Этот код под ОС Windows также зависит от наличия в последней строке файла символа перевода строки, надежнее было бы сделать так:

      Явные вызовы методов open и close не обязательны. Действительно, вызов конструктора с аргументом позволяет сразу же, в момент создания поточного объекта file , открыть файл:

      Вместо метода close можно использовать оператор delete , который автоматически вызовет деструктор объекта file и закроет файл. Код цикла while обеспечивает надлежащую проверку признака конца файла.

      Класс ofstream: запись файлов

      Класс ofstream предназначен для вывода данных из файлового потока. Далее перечислены основные методы данного класса.

      Метод Описание
      open Открывает файл для записи
      put Записывает одиночный символ в файл
      write Записывает заданное число байт из памяти в файл
      seekp Перемещает указатель позиционирования в указанное положение
      tellp Возвращает текущее значение указателя позиционирования файла
      close Закрывает файл

      Описанный ранее оператор включения удобен для организации записи в текстовый файл:

      Бинарные файлы

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

      Первый параметр методов write и read (адрес блока записи/чтения) должен иметь тип символьного указателя char * , поэтому необходимо произвести явное преобразование типа адреса структуры void * . Второй параметр указывает, что бинарные блоки файла имеют постоянный размер байтов независимо от фактической длины записи. Следующее приложение дает пример создания и отображения данных простейшей записной книжки. Затем записи файла последовательно считываются и отображаются на консоли.

      P.S. При выполнении этого и других листингов в Visual Studio последних версий может дополнительно понадобиться подключение директивы _CRT_SECURE_NO_WARNINGS.

      В результате выполнения этого кода образуется бинарный файл Notebook.dat из трех блоков размером по 80 байт каждый (при условии, что символы - однобайтовые). Естественно, вы можете использовать другие поточные методы и проделывать любые операции над полями определенной структуры данных.

      Класс fstream: произвольный доступ к файлу

      Предположим что в нашей записной книжке накопилось 100 записей, а мы хотим считать 50-ю. Конечно, можно организовать цикл и прочитать все записи с первой по заданную. Очевидно, что более целенаправленное решение - установить указатель позиционирования файла pos прямо на запись 50 и считать ее:

      Подобные операции поиска эффективны, если файл состоит из записей известного и постоянного размера. Чтобы заменить содержимое произвольной записи, надо открыть поток вывода в режиме модификации:

      Если не указать флаг ios::ate (или ios::app ), то при открытии бинарного файла Notebook.dat его предыдущее содержимое будет стерто!

      Дополнительно может понадобиться указать, откуда отсчитывается смещение.

      Наконец, можно открыть файл одновременно для чтения/записи, используя методы, унаследованные поточным классом fstream от своих предшественников. Поскольку класс fstream произведен от istream и ostream (родителей ifstream и ofstream соответственно), все упомянутые ранее методы становятся доступными в приложении.

      Читайте также: