Как записать на си в файл. Работа с файлами в Си-шарп. Классы StreamReader и StreamWriter

Большинство компьютерных программ работают с файлами, и поэтому возникает необходимость создавать, удалять, записывать читать, открывать файлы. Что же такое файл? Файл – именованный набор байтов, который может быть сохранен на некотором накопителе. Ну, теперь ясно, что под файлом понимается некоторая последовательность байтов, которая имеет своё, уникальное имя, например файл.txt . В одной директории не могут находиться файлы с одинаковыми именами. Под именем файла понимается не только его название, но и расширение, например: file.txt и file.dat разные файлы, хоть и имеют одинаковые названия. Существует такое понятие, как полное имя файлов – это полный адрес к директории файла с указанием имени файла, например: D:\docs\file.txt . Важно понимать эти базовые понятия, иначе сложно будет работать с файлами.

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

Чтение файла строки вдоль строки

Вот общая структура кода для чтения содержимого файла. Как вы можете видеть, ничего нового здесь нет. Файл можно прочитать тремя способами. Ниже приведено подробное описание каждого из этих методов. Этот метод включает чтение одной строки текста и запись ее в виде строки.

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

Файловый ввод/вывод аналогичен стандартному вводу/выводу, единственное отличие – это то, что ввод/вывод выполнятся не на экран, а в файл. Если ввод/вывод на стандартные устройства выполняется с помощью объектов cin и cout , то для организации файлового ввода/вывода достаточно создать собственные объекты, которые можно использовать аналогично операторам cin и cout .

Читая слово слово за словом

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

Чтение файла символа после символа

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

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

Например, необходимо создать текстовый файл и записать в него строку Работа с файлами в С++ . Для этого необходимо проделать следующие шаги:

  1. создать объект класса ofstream ;
  2. связать объект класса с файлом, в который будет производиться запись;
  3. записать строку в файл;
  4. закрыть файл.

Почему необходимо создавать объект класса ofstream , а не класса ifstream ? Потому, что нужно сделать запись в файл, а если бы нужно было считать данные из файла, то создавался бы объект класса ifstream .

Когда мы загружаем текстовую строку, мы можем делать это с тем, что нам нравится. Эта программа только поочередно отображает каждую строку контента, но в реальной программе они будут использоваться по-другому. Единственное ограничение - ваше воображение.

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

// создаём объект для записи в файл ofstream /*имя объекта*/; // объект класса ofstream

Назовём объект – fout , Вот что получится:

Ofstream fout;

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

Fout.open("cppstudio.txt"); // связываем объект с файлом

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

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

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

Fout << "Работа с файлами в С++"; // запись строки в файл

На мгновение мы углубимся в технические детали, чтобы точно знать, как читать содержимое файла. Когда мы открываем файл в текстовом редакторе, таком как «Блокнот», мы найдем курсор в текстовом редакторе, указывающий, где мы находимся. Когда вы нажимаете клавишу на клавиатуре, в точке, где находится курсор, появляется новая буква.

Это означает, что таким образом содержимое файла можно просматривать только последовательно. К счастью, есть способы изменить положение курсора в файле. Например, вы можете переместить его до 20 мест с начала файла или 32 символа вперед в текущую позицию. Это позволяет вам точно прочитать те части интересующего нас файла.

Используя операцию передачи в поток совместно с объектом fout строка Работа с файлами в С++ записывается в файл. Так как больше нет необходимости изменять содержимое файла, его нужно закрыть, то есть отделить объект от файла.

Fout.close(); // закрываем файл

Итог – создан файл со строкой Работа с файлами в С++ .

Шаги 1 и 2 можно объединить, то есть в одной строке создать объект и связать его с файлом. Делается это так:

Проверка положения курсора в файле

Однако для этого сначала вам нужно выяснить, где находится файл. Только тогда мы можем переместить курсор. Ниже вы узнаете, как это сделать. Существуют специальные функции для проверки того, какой байт в файле указывает на курсор. Другими словами, эти функции позволяют вам видеть, какой символ является курсором в данный момент. К счастью, они используются одинаково. Эти функции также используются таким же образом, поэтому приведен пример использования только одного из них.

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

Ofstream fout("cppstudio.txt"); // создаём объект класса ofstream и связываем его с файлом cppstudio.txt

Объединим весь код и получим следующую программу.

// file.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include using namespace std; int main(int argc, char* argv) { ofstream fout("cppstudio.txt"); // создаём объект класса ofstream для записи и связываем его с файлом cppstudio.txt fout << "Работа с файлами в С++"; // запись строки в файл fout.close(); // закрываем файл system("pause"); return 0; }

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

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

Осталось проверить правильность работы программы, а для этого открываем файл cppstudio.txt и смотрим его содержимое, должно быть — Работа с файлами в С++ .

  1. создать объект класса ifstream и связать его с файлом, из которого будет производиться считывание;
  2. прочитать файл;
  3. закрыть файл.
#include using namespace std; int main(int argc, char* argv) { setlocale(LC_ALL, "rus"); // корректное отображение Кириллицы char buff; // буфер промежуточного хранения считываемого из файла текста ifstream fin("cppstudio.txt"); // открыли файл для чтения fin >> << buff << endl; // напечатали это слово fin.getline(buff, 50); // считали строку из файла fin.close(); // закрываем файл cout << buff << endl; // напечатали эту строку system("pause"); return 0; }

В программе показаны два способа чтения из файла, первый – используя операцию передачи в поток, второй – используя функцию getline() . В первом случае считывается только первое слово, а во втором случае считывается строка, длинной 50 символов. Но так как в файле осталось меньше 50 символов, то считываются символы включительно до последнего. Обратите внимание на то, что считывание во второй раз (строка 17 ) продолжилось, после первого слова, а не с начала, так как первое слово было прочитано в строке 14 . Результат работы программы показан на рисунке 1.

Используйте эту команду, чтобы показать пример. Концепция индикатора будет объяснена в следующем классе, поэтому им больше не нужно будет знать об этом. Имея уже обработанные отдельные переменные, а также группы переменных как массивы, мы можем пойти еще на один шаг. Это в основном то, что подразумевает название.

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

Работа с файлами в С++ Для продолжения нажмите любую клавишу. . .

Рисунок 1 — Работа с файлами в С++

Программа сработала правильно, но не всегда так бывает, даже в том случае, если с кодом всё впорядке. Например, в программу передано имя несуществующего файла или в имени допущена ошибка. Что тогда? В этом случае ничего не произойдёт вообще. Файл не будет найден, а значит и прочитать его не возможно. Поэтому компилятор проигнорирует строки, где выполняется работа с файлом. В результате корректно завершится работа программы, но ничего, на экране показано не будет. Казалось бы это вполне нормальная реакции на такую ситуацию. Но простому пользователю не будет понятно, в чём дело и почему на экране не появилась строка из файла. Так вот, чтобы всё было предельно понятно в С++ предусмотрена такая функция — is_open() , которая возвращает целые значения: 1 — если файл был успешно открыт, 0 — если файл открыт не был. Доработаем программу с открытием файла, таким образом, что если файл не открыт выводилось соответствующее сообщение.

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

То же самое относится к аргументам, так как можно писать функции, которые не принимают никаких аргументов. Вы понимаете, почему это выглядит и почему оно наконец возвращается? К счастью, этого не должно быть. В конце концов, у нас есть огромные области энергонезависимой памяти, которые являются нашим жестким диском. Мы можем сохранять любую информацию в файлах, а затем читать в любое время. Большинство программ сохраняют свои настройки в файлах, поэтому они могут меняться сразу же после их запуска.

// file_read.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include #include using namespace std; int main(int argc, char* argv) { setlocale(LC_ALL, "rus"); // корректное отображение Кириллицы char buff; // буфер промежуточного хранения считываемого из файла текста ifstream fin("cppstudio.doc"); // (ВВЕЛИ НЕ КОРРЕКТНОЕ ИМЯ ФАЙЛА) if (!fin.is_open()) // если файл не открыт cout << "Файл не может быть открыт!\n"; // сообщить об этом else { fin >> buff; // считали первое слово из файла cout << buff << endl; // напечатали это слово fin.getline(buff, 50); // считали строку из файла fin.close(); // закрываем файл cout << buff << endl; // напечатали эту строку } system("pause"); return 0; }

Это связано с тем, что имя файла излишне занимает память программы, а не единственное число. Преобразование имени файла, к счастью, встроено в команды, и нам не нужно иметь дело с ним. Давайте перейдем к началу фрагмента кода, а затем объясним, что будет дальше в программе. В конце программы обязательно закройте этот файл. Если мы не называем это, мы не можем видеть никаких данных в файле, который мы написали. Когда запускать, где искать наш файл? Если мы хотим обрабатывать файлы в другом месте, мы можем использовать.

Фактически, на самом деле это так. Каждая программа при запуске получает доступ к 3 потокам. Доступны следующие режимы. Мы не будем использовать его во время этой лаборатории. Мы также изучим команды, которые мы будем использовать в следующих случаях.

Результат работы программы показан на рисунке 2.

Файл не может быть открыт! Для продолжения нажмите любую клавишу. . .

Рисунок 2 — Работа с файлами в С++

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

Запись и чтение - символ по символу

Существуют также те, которые обрабатывают персонаж персонажем. Из этих примеров мы узнали несколько вещей.

Запись и чтение - по очереди

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

Он не вставляет конец строки, если мы хотим этого, мы должны добавить его сами. . Напишите функцию, которую будут отображать 3 целых числа, заданные пользователем, от минимального до самого большого. Напишите функцию, которая информирует пользователя с соответствующим сообщением о том, принадлежат ли три его стороны треугольнику прямоугольному треугольнику. Данные, данные пользователем, - это двойные числа.

Режимы открытия файлов

Режимы открытия файлов устанавливают характер использования файлов. Для установки режима в классе ios_base предусмотрены константы, которые определяют режим открытия файлов (см. Таблица 1).

Режимы открытия файлов можно устанавливать непосредственно при создании объекта или при вызове функции open() .

Напишите программу, которая отображает, является ли данный номер четным. Проверьте его работу в программе. Напишите программу, которая переписывает файл во второй файл, только с конца. Подсчитайте количество символов в каждой строке. В зависимости от его выбора программа должна писать в конце, например, 3 2 = 5. В этой статье описывается базовый доступ к файлам. Вы будете знать полную основу файловой системы. Вы узнаете, что такое двоичный файл и как он отличается от текстового файла. Вы узнаете больше о режимах доступа к файлам.

Наконец, вы напишете свою собственную программу, которая будет записывать данные в файл и отображать его содержимое. Теперь на жестком диске компьютера можно разместить определенный объем данных, современные жесткие диски имеют емкость от нескольких сотен гигабайт до нескольких терабайт. Каждый из этих байтов составляет 8 бит.

Ofstream fout("cppstudio.txt", ios_base::app); // открываем файл для добавления информации к концу файла fout.open("cppstudio.txt", ios_base::app); // открываем файл для добавления информации к концу файла

Режимы открытия файлов можно комбинировать с помощью поразрядной логической операции или | , например: ios_base::out | ios_base::trunc — открытие файла для записи, предварительно очистив его.

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

Двоичные файлы и текстовые файлы

Вы уже знаете, что файл сопоставляется с определенной областью данных на диске. Открывая любой файл, вы читаете эти данные через файловую систему. Эти данные могут быть сохранены в режиме «текст» или «двоичный». Способ сохранения данных существенно влияет на размер файла. Написание того же номера, что и строка в текстовом файле, требует 7 байтов. Другими словами, двоичная запись в подавляющем большинстве случаев требует меньшего дискового пространства.

Объекты класса ofstream , при связке с файлами по умолчанию содержат режимы открытия файлов ios_base::out | ios_base::trunc . То есть файл будет создан, если не существует. Если же файл существует, то его содержимое будет удалено, а сам файл будет готов к записи. Объекты класса ifstream связываясь с файлом, имеют по умолчанию режим открытия файла ios_base::in — файл открыт только для чтения. Режим открытия файла ещё называют — флаг, для удобочитаемости в дальнейшем будем использовать именно этот термин. В таблице 1 перечислены далеко не все флаги, но для начала этих должно хватить.

К сожалению, это связано с некоторыми ограничениями. Теперь двоичные файлы не читаются для людей. Вы когда-нибудь открывали двоичный файл в записках? Затем вы увидите пресловутые «кусты», потому что ноутбук интерпретирует двоичные данные как текст. Файловая система организует данные на диске в иерархической структуре каталогов, в которых находятся файлы. Каждый файл или каталог имеет путь, который однозначно идентифицирует свое место в этой структуре.

Здесь мы сталкиваемся с некоторыми различиями между различными операционными системами. Это связано с тем, что символ \\ используется особым образом. Мы также можем говорить об относительном пути. Вы должны знать, что файл можно открыть «читать», «написать» или «в режиме вложения». Этот режим очень важен, открытие для записи файла, который уже существует и сохранение даже одного символа, стирает весь существующий контент. Аналогично, открытие файла, который еще не существует, создаст файл, который еще не существует.

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

Разработаем программу, которая, используя операцию sizeof() , будет вычислять характеристики основных типов данных в С++ и записывать их в файл. Характеристики:

  1. число байт, отводимое под тип данных
  2. максимальное значение, которое может хранить определённый тип данных.

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

/* data type byte max value bool = 1 255.00 char = 1 255.00 short int = 2 32767.00 unsigned short int = 2 65535.00 int = 4 2147483647.00 unsigned int = 4 4294967295.00 long int = 4 2147483647.00 unsigned long int = 4 4294967295.00 float = 4 2147483647.00 long float = 8 9223372036854775800.00 double = 8 9223372036854775800.00 */

Такая программа уже разрабатывалась ранее в разделе , но там вся информация о типах данных выводилась на стандартное устройство вывода, а нам необходимо программу переделать так, чтобы информация записывалась в файл. Для этого необходимо открыть файл в режиме записи, с предварительным усечением текущей информации файла (строка 14 ). Как только файл создан и успешно открыт (строки 16 — 20), вместо оператора cout , в строке 22 используем объект fout . таким образом, вместо экрана информация о типах данных запишется в файл.

// write_file.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include #include // работа с файлами #include // манипуляторы ввода/вывода using namespace std; int main(int argc, char* argv) { setlocale(LC_ALL, "rus"); // связываем объект с файлом, при этом файл открываем в режиме записи, предварительно удаляя все данные из него ofstream fout("data_types.txt", ios_base::out | ios_base::trunc); if (!fout.is_open()) // если файл небыл открыт { cout << "Файл не может быть открыт или создан\n"; // напечатать соответствующее сообщение return 1; // выполнить выход из программы } fout << " data type " << "byte" << " " << " max value " << endl // заголовки столбцов << "bool = " << sizeof(bool) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных bool*/ << (pow(2,sizeof(bool) * 8.0) - 1) << endl << "char = " << sizeof(char) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных char*/ << (pow(2,sizeof(char) * 8.0) - 1) << endl << "short int = " << sizeof(short int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных short int*/ << (pow(2,sizeof(short int) * 8.0 - 1) - 1) << endl << "unsigned short int = " << sizeof(unsigned short int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных unsigned short int*/ << (pow(2,sizeof(unsigned short int) * 8.0) - 1) << endl << "int = " << sizeof(int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных int*/ << (pow(2,sizeof(int) * 8.0 - 1) - 1) << endl << "unsigned int = " << sizeof(unsigned int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных unsigned int*/ << (pow(2,sizeof(unsigned int) * 8.0) - 1) << endl << "long int = " << sizeof(long int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных long int*/ << (pow(2,sizeof(long int) * 8.0 - 1) - 1) << endl << "unsigned long int = " << sizeof(unsigned long int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных undigned long int*/ << (pow(2,sizeof(unsigned long int) * 8.0) - 1) << endl << "float = " << sizeof(float) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных float*/ << (pow(2,sizeof(float) * 8.0 - 1) - 1) << endl << "long float = " << sizeof(long float) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных long float*/ << (pow(2,sizeof(long float) * 8.0 - 1) - 1) << endl << "double = " << sizeof(double) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных double*/ << (pow(2,sizeof(double) * 8.0 - 1) - 1) << endl; fout.close(); // программа больше не использует файл, поэтому его нужно закрыть cout << "Данные успешно записаны в файл data_types.txt\n"; system("pause"); return 0; }

Нельзя не заметить, что изменения в программе минимальны, а всё благодаря тому, что стандартный ввод/вывод и файловый ввод/вывод используются абсолютно аналогично. В конце программы, в строке 45 мы явно закрыли файл, хотя это и не обязательно, но считается хорошим тоном программирования. Стоит отметить, что все функции и манипуляторы используемые для форматирования стандартного ввода/вывода актуальны и для файлового ввода/вывода. Поэтому не возникло никаких ошибок, когда оператор cout был заменён объектом fout .

Особенности языка С. Учебное пособие

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

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

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

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

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

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

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

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

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

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

fscanf()

Функция fscanf() аналогична по смыслу функции scanf() , но в отличии от нее осуществляет форматированный ввод из файла, а не стандартного потока ввода. Функция fscanf() принимает параметры: файловый указатель, строку формата, адреса областей памяти для записи данных:
fscanf (myfile, "%s%d" , str, & a) ;

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

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

Apples 10 23.4 bananas 5 25.0 bread 1 10.3

#include main () { FILE * file; struct food { char name[ 20] ; unsigned qty; float price; } ; struct food shop[ 10] ; char i= 0 ; file = fopen("fscanf.txt" , "r" ) ; while (fscanf (file, "%s%u%f" , shop[ i] .name , & (shop[ i] .qty ) , & (shop[ i] .price ) ) != EOF) { printf ("%s %u %.2f\n " , shop[ i] .name , shop[ i] .qty , shop[ i] .price ) ; i++; } }

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

fgets()

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

Например:
fgets (str, 50 , myfile)

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

#include #define N 80 main () { FILE * file; char arr[ N] ; file = fopen("fscanf.txt" , "r" ) ; while (fgets (arr, N, file) != NULL) printf ("%s" , arr) ; printf ("\n " ) ; fclose(file) ; }

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

getc() или fgetc()

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

while ((arr[ i] = fgetc (file) ) != EOF) { if (arr[ i] == "\n " ) { arr[ i] = "\0 " ; printf ("%s\n " , arr) ; i = 0 ; } else i++; } arr[ i] = "\0 " ; printf ("%s\n " , arr) ;

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

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

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

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

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

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

file = fopen("fprintf.txt" , "w" ) ; while (scanf ("%s%u%f" , shop[ i] .name , & (shop[ i] .qty ) , & (shop[ i] .price ) ) != EOF) { fprintf(file, "%s %u %.2f\n " , shop[ i] .name , shop[ i] .qty , shop[ i] .price ) ; i++; }

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

while (gets (arr) != NULL) { fputs(arr, file) ; fputs("\n " , file) ; }

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

while ((i = getchar() ) != EOF) putc(i, file) ;

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

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

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

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

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

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

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

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

#include #include main () { FILE * file; char shelf1[ 50] , shelf2[ 100] ; int n, m; file = fopen("shelf1.txt" , "rb" ) ; n= fread(shelf1, sizeof (char ) , 50, file) ; fclose(file) ; file = fopen("shelf2.txt" , "rb" ) ; m= fread(shelf2, sizeof (char ) , 50, file) ; fclose(file) ; shelf1[ n] = "\0 " ; shelf2[ m] = "\n " ; shelf2[ m+ 1 ] = "\0 " ; file = fopen("shop.txt" , "wb" ) ; fwrite(strcat(shelf2, shelf1) , sizeof (char ) , n+ m, file) ; fclose(file) ; }

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

Решение задач

Задание

  1. Напишите программу, которая запрашивает у пользователя имя (адрес) текстового файла, далее открывает его и считает в нем количество символов и строк.
  2. Напишите программу, которая записывает в файл данные, полученные из другого файла и так или иначе измененные перед записью. Каждая строка данных, полученная из файла, должна помещаться в структуру.


Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: