Какой заголовочный файл с содержит инструкции файлового ввода вывода

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

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

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

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

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

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

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

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

ofstream fout;

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

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

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

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

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

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

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

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

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

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

// file.cpp: определяет точку входа для консольного приложения.

#include "stdafx.h"
#include <fstream>
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. закрыть файл.
// file_read.cpp: определяет точку входа для консольного приложения.

#include "stdafx.h"
#include <fstream>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
    setlocale(LC_ALL, "rus"); // корректное отображение Кириллицы
    char buff[50]; // буфер промежуточного хранения считываемого из файла текста
    ifstream fin("cppstudio.txt"); // открыли файл для чтения

    fin >> buff; // считали первое слово из файла
    cout << buff << endl; // напечатали это слово

    fin.getline(buff, 50); // считали строку из файла
    fin.close(); // закрываем файл
    cout << buff << endl; // напечатали эту строку

    system("pause");
    return 0;
}

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

CppStudio.com

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

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

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

// file_read.cpp: определяет точку входа для консольного приложения.

#include "stdafx.h"
#include <fstream>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
    setlocale(LC_ALL, "rus"); // корректное отображение Кириллицы
    char buff[50]; // буфер промежуточного хранения считываемого из файла текста
    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;
}

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

CppStudio.com

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

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

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

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

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

Таблица 1 — режимы открытия файлов

Константа Описание
ios_base::in открыть файл для чтения
ios_base::out открыть файл для записи
ios_base::ate при открытии переместить указатель в конец файла
ios_base::app открыть файл для записи в конец файла
ios_base::trunc удалить содержимое файла, если он существует
ios_base::binary открытие файла в двоичном режиме

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

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

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

Объекты класса 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 <iostream>
#include <fstream> // работа с файлами
#include <iomanip> // манипуляторы ввода/вывода
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.txtn";
    system("pause");
    return 0;
}

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

Стандартные потоки ввода-вывода

Программа, выводящая в консоль сообщение Hello, world!, с которой традиционно начинают изучение языка программирования, на языке C++ выглядит следующим образом:

#include <iostream>

using namespace std;

int main() {
    cout << "Hello, world!" << endl;
    return 0;
}

Директива #include и функция main() знакомы читателю по языку C. Способ вывода строки в консоль отличается от стандартной функции printf языка C и даёт нам повод начать разговор про C++.

Глобальный объект cout отвечает за вывод в стандартный поток вывода stdout. Оператор вставки << передает различные объекты в поток вывода. Манипулятор endl выполняет перевод строки. Оператор << позволяет строить цепочки вызовов, которые будут выполняться слева направо: сначала мы вывели строку Hello, world!, а затем манипулятор endl.

Чтобы считать данные из стандартного потока ввода stdin, необходимо воспользоваться объектом cin и оператором извлечения >>.

int a;
double x;

cin >> a >> x;

Здесь мы снова построили цепочку вызовов и получили значения сразу для двух переменных. При обращении к потоку ввода мы не указывали тип данных, которые необходимо прочитать. Оператор >> сам определяет типы объектов и заполняет их из потока ввода.

Объекты cout, cin, а также операторы вставки и извлечения определены в заголовочном файле <iostream>

Работа с файлами

Все операции ввода-вывода в C++ организованы через потоки и операторы << и >>. Мы уже рассмотрели операции ввода-вывода в потоки stdout и stdin. Операции ввода-вывода с файлами устроены схожим образом. Для работы с файловыми потоками необходимо подключить заголовочный файл <fstream>. Следующая программа создает файл test.txt и записывает в него строку Hello, world!

#include <fstream>

using namespace std;

int main() {
    ofstream ofile("test.txt", ios::out);
    if (ofile.is_open()) {
        ofile << "Hello, world!";
    }

    return 0;
}

Сначала мы создали объект типа ofstream. В его конструктор мы передали имя файла test.txt и флаг ios::out, указывающий на то, что мы собираемся осуществлять операции вывода. Всегда необходимо проверять, что операция открытия/создания файла прошла успешно. Если не выполнить эту проверку, то, если по какой-либо причине файл открыть не удалось, дальнейшие шаги приведут к аварийному завершению программы. Метод is_open() позволяет выполнить такою проверку. Дальше идет уже знакомый нам вызов оператора <<, который в этом случае работает с файловым потоком вывода. Обратите внимание, что нет необходимости вручную закрывать файл, если того не требует логика программы. При выходе объекта ofile из области видимости, файл будет корректно закрыт.

Чтение данных из файла производится следующим образом:

#include <fstream>
#include <string>
#include <iostream>

using namespace std;

int main() {
    ifstream ifile("test.txt", ios::in);
    if (ifile.is_open()) {
        string line;
        while (ifile >> line) {
            cout << line << ' ';
        }
    }

    return 0;
}

Здесь мы воспользовались файловым потоком ввода ifstream и флагом ios::in. В этой программе мы создали переменную line типа string, чтобы хранить считанные из файла данные. Неочевидным моментом здесь является использование цикла while. Дело в том, что оператор >> считывает символы до тех пор, пока не встретит разделитель (пробел, табуляция или перенос строки). Если бы мы вызвали этот оператор один раз, то в переменную line было бы записано Hello,, а это не то, чего мы хотели. Цикл позволяет прочитать файл до конца.

Если же мы хотим прочитать только одну строчку из файла, то можно воспользоваться функцией getline, определенной в <string>. С этой функцией наша программа примет следующий вид:

#include <fstream>
#include <string>
#include <iostream>

using namespace std;

int main() {
    ifstream ifile("test.txt", ios::in);
    if (ifile.is_open()) {
        string line;
        getline(ifile, line);
        cout << line << end;
    }

    return 0;
}

Наконец, для чтения символов из потока по одному можно использовать метод get()

char c;
while (ifile.get(c)) {
    cout << c;
}

Аналогичный метод есть и у объекта cin.

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

Строковые потоки

Часто бывает удобно работать со строковыми потоками. Инструменты для работы со строковыми потоками подключаются с помощью заголовочного файла <sstream>. Строковые потоки позволяют удобно инициализировать объекты различных типов из их текстового представления. Представим себе, что мы получили географические координаты НГУ в виде строки "(54.847830, 83.094392)". Наша задача извлечь из строки две величины типа double. Сделать это можно следующим образом:

#include <string>
#include <sstream>
#include <iostream>

using namespace std;

int main() {
    string nsucoor("(54.847830, 83.094392)");

    stringstream ss(nsucoor);
    double lat, lon;
    ss.ignore(1);  // skip '('
    ss >> lat;
    ss.ignore(2);  // skip ", "
    ss >> lon;
    cout << lat << ", " << lon << endl;

    return 0;
}

Резюме

Мы обсудили, что все операции ввода-вывода в С++ реализованы единообразно с помощью потоков. Вывод в поток осуществляется с помощью оператора вставки <<, ввод из потока осуществляется с помощью оператора извлечения >>. Мы рассмотрели три типа потоков: стандартные, файловые и строковые. Этого достаточно для уверенного начала работы с потоками ввода-вывода в C++.

Документация

  • http://www.cplusplus.com/reference/iolibrary/
  • https://en.cppreference.com/w/cpp/io
 

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

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

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

  • <ifstream> — файловый ввод ;
  • <ofstream> — файловый вывод.

Файловый ввод-вывод аналогичен стандартному вводу-выводу, единственное отличие – это то, что ввод-вывод выполнятся не на экран, а в файл.

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

При работе с файлом можно выделить следующие этапы:

  • создать объект класса fstream (возможно, ofstream или ifstream);
  • связать объект класса fstream с файлом, который будет использоваться для операций ввода-вывода;
  • осуществить операции ввода-вывода в файл;
  • закрыть файл.

1
2
3
4
5
6
7
8
9
10

#include <fstream>
using namespace std;
int main()
{
  ofstream fout;
  fout.open(«file.txt»);
  fout << «Привет, мир!»;
  fout.close();
  return 0;
}

В результате будет создан файл
Работа с файлами в C++

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

Константа Описание
ios::in открыть файл для чтения
ios::out открыть файл для записи
ios::ate при открытии переместить указатель в конец файла
ios::app открыть файл для записи в конец файла
ios::trunc удалить содержимое файла, если он существует
ios::binary открытие файла в двоичном режиме

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

ofstream fout(«file.txt», ios::app);
fout.open(«file.txt», ios::app);

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

ios::out | ios::in — открытие файла для записи и чтения.

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

Система ввода-вывода С++ позволяет осуществлять произвольный доступ с использованием методов seekg() и seekp().

  • ifstream &seekg(Смещение, Позиция);
  • ofstream &seekp(Смещение, Позиция);

Смещение определяет область значений в пределах файла (long int).

Система ввода-вывода С++ обрабатывает два указателя, ассоциированные с каждым файлом:

  • get pointer g — определяет, где именно в файле будет производиться следующая операция ввода;
  • put pointer p — определяет, где именно в файле будет производиться следующая операция вывода.

Позиция смещения определяется как

Позиция Значение
ios::beg Начало файла
ios::cur Текущее положение
ios::end Конец файла

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

Можно определить текущую позицию файлового указателя, используя следующие функции:

  • streampos tellg() — позиция для ввода
  • streampos tellp() — позиция для вывода

 
Пример на С++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
  system(«chcp 1251»);
  system(«cls»);
  char s[80];
  fstream inOut;
  inOut.open(«file.txt», ios::out);
  inOut << «строчка текста» << endl;
  inOut.seekp(8, ios::beg);
  inOut << «еще строчка текста»;
  inOut.close();
  inOut.open(«file.txt», ios::in);
  inOut.seekg(-6, ios::end);
  inOut >> s;
  inOut.close();
  cout << s;
  cin.get();
  return 0;
}

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

Ещё один пример. Допустим, нам нужно заполнять таблицу

Причем каждая вновь введенная строка должна размещаться в таблице непосредственно под «шапкой».

Алгоритм решения задачи следующий:

  • формируем очередную строку для вывода
  • открываем файл для чтения, считываем из него данные и сохраняем их в массив строк
  • закрываем файл
  • открываем файл для записи
  • выводим «шапку» таблицы
  • выводим новую строку
  • выводим все сохраненные строки обратно в файл, начиная со строки после шапки

Пример на C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

#include <iostream>
#include <fstream>
using namespace std;
#define LINES 100 // максимальное количество строк в файле
int main() {
  system(«chcp 1251»);
  system(«cls»);
  char line[LINES][100];
  char str[30];
  char s[] = «|                              |                |                              |»;
  // Ввод данных для размещаемой строки
  cout << «ФИО: «;
  cin.getline(str, 30); // вводим ФИО
  for (int i = 0; str[i] != »; i++) // копируем в строку без 0
    s[i + 2] = str[i];               // начиная с указанной позиции
  cout << «Дата: «;
  cin.getline(str,30);
  for (int i = 0; str[i] != »; i++)
    s[i + 33] = str[i];
  cout << «Хобби: «;
  cin.getline(str,30);
  for (int i = 0; str[i] != »; i++)
    s[i + 50] = str[i];

    fstream inOut;
  inOut.open(«file.txt»,  ios::in); // открываем файл для ввода
  // Считываем из файла имеющиеся данные
  int count = 0;
  while (inOut.getline(line[count], 100)) count++;
  inOut.close(); // закрываем файл

    inOut.open(«file.txt», ios::out); // открываем файл для вывода
  inOut << «———————————————————————————« << endl;
  inOut << «|   ФИО                        |  Дата          | Хобби                        |» << endl;
  inOut << «———————————————————————————« << endl;
  inOut << s << endl; // выводим сформированную строку
  inOut << «———————————————————————————« << endl;
  // Выводим обратно в файл все строки кроме «шапки» (первые 3 строки)
  for (int j = 3; j < count; j++)
  {
    inOut << line[j] << endl;
  }
  inOut.close();
  cin.get();
  return 0;
}

Результат выполнения:
Ввод строки таблицы
Ввод строки таблицы
Ввод строки таблицы

Полученный файл данных:
Файл данных

Назад: Язык C++

По мере усложнения ваших программ они будут сохранять и получать информацию, используя файлы. Если вы знакомы с файловыми манипуляциями в языке С, вы сможете использовать подобные методы и в C++. Кроме того, как вы узнаете из этого урока, C++ предоставляет набор классов файловых потоков, с помощью которых можно очень легко выполнять операции ввода и вывода (В/В) с файлами. К концу данного урока вы освоите следующие основные концепции:

  • Используя выходной файловый поток, вы можете писать информацию в файл с помощью оператора вставки (<<).
  • Используя входной файловый поток, вы можете читать хранимую в файле информацию с помощью оператора извлечения (>>).
  • Для открытия и закрытия файла вы используете методы файловых классов.
  • Для чтения и записи файловых данных вы можете использовать операторы вставки и извлечения, а также некоторые методы файловых классов.

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

ВЫВОД В ФАЙЛОВЫЙ ПОТОК

Из урока 33 вы узнали, что cout представляет собой объект типа ostream(выходной поток). Используя класс ostream, ваши программы могут выполнять вывод в cout с использованием оператора вставки или различных методов класса, например cout.put. Заголовочный файлiostream.h определяет выходной поток cout. Аналогично, заголовочный файл f stream.h определяет класс выходного файлового потока с именемofstream. Используя объекты класса ofstream, ваши программы могут выполнять вывод в файл. Для начала вы должны объявить объект типаofstream, указав имя требуемого выходного файла как символьную строку, что показано ниже:

ofstream file_object(«FILENAME.EXT»);

Если вы указываете имя файла при объявлении объекта типа ofstream, C++ создаст новый файл на вашем диске, используя указанное имя, или перезапишет файл с таким же именем, если он уже существует на вашем диске Следующая программа OUT_FILE.CPP создает объект типа ofstreamи затем использует оператор вставки для вывода нескольких строк текста в файл BOOKINFO.DAT:

#include <fstream.h>

void main(void)

{
ofstream book_file(«BOOKINFO.DAT»);
book_file << «Учимся программировать на языке C++, » << «Вторая редакция» << endl;
book_file << «Jamsa Press» << endl;
book_file << «22.95» << endl;
}

В данном случае программа открывает файл BOOKINFO.DAT и затем записывает три строки в файл, используя оператор вставки. Откомпилируйте и запустите эту программу. Если вы работаете в среде MS-DOS, можете использовать команду TYPE для вывода содержимого этого файла на экран:

С:> TYPE BOOKINFO.DAT <ENTER>

Учимся программировать на языке C++, Вторая редакция

Jamsa Press

$22.95

Как видите, в C++ достаточно просто выполнить операцию вывода в файл.

ЧТЕНИЕ ИЗ ВХОДНОГО ФАЙЛОВОГО ПОТОКА

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

ifstream input_file(«filename.EXT»);

Следующая программа FILE_IN.CPP открывает файл BOOKINFO.DAT, который вы создали с помощью предыдущей программы, и читает, а затем отображает первые три элемента файла:

#include <iostream.h>

#include <fstream.h>

void main(void)

{
ifstream input_file(«BOOKINFO.DAT») ;
char one[64], two[64], three[64];
input_file >> one;
input_file >> two;
input_file >> three;
cout << one << endl;
cout << two << endl;
cout << three << endl;
}

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

С:> FILE_IN <ENTER>

учимся

программировать

на

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

Из урока 33 вы узнали, что ваши программы могут использовать cin.getlineдля чтения целой строки с клавиатуры. Подобным образом объекты типаifstream могут использовать getline для чтения строки файлового ввода. Следующая программа FILELINE.CPP использует функцию getline для чтения всех трех строк файла BOOKINFO.DAT:

#include <iostream.h>

#include <fstream.h>

void main(void)

{
ifstream input_file(«BOOKINFO.DAT»);
char one[64], two[64], three [64] ;
input_file.getline(one, sizeof(one)) ;
input_file.get line(two, sizeof(two));
input_file.getline(three, sizeof(three)) ;
cout << one << endl;
cout << two << endl;
cout << three << endl;
}

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

ОПРЕДЕЛЕНИЕ КОНЦА ФАЙЛА

Обычной файловой операцией в ваших программах является чтение содержимого файла, пока не встретится конец файла. Чтобы определить конец файла, ваши программы могут использовать функцию еоf потокового объекта. Эта функция возвращает значение 0, если конец файла еще не встретился, и 1, если встретился конец файла. Используя цикл while, ваши программы могут непрерывно читать содержимое файла, пока не найдут конец файла, как показано ниже:

while (! input_file.eof())

{
// Операторы
}

В данном случае программа будет продолжать выполнять цикл, пока функция eof возвращает ложь (0). Следующая программа TEST_EOF.CPP использует функцию eof для чтения содержимого файла BOOKINFO.DAT, пока не достигнет конца файла:

#include <iostream.h>

#include <fstream.h>

void main (void)

{
ifstream input_file(«BOOKINFO.DAT»);
char line[64];
while (! input_file.eof())

{
input_file.getline(line, sizeof(line));
cout << line << endl;
}
}

Аналогично, следующая программа WORD_EOF.CPP читает содержимое файла по одному слову за один раз, пока не встретится конец файла:

#include <iostream.h>

#include <fstream.h>

void main(void)

{
ifstream input_file(«BOOKINFO.DAT»);
char word[64] ;
while (! input_file.eof())

{
input_file >> word;
cout << word << endl;
}
}

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

#include <iostream.h>

#include <fstream.h>

void main(void)

{
ifstream input_file(«BOOKINFO.DAT»);
char letter;
while (! input_file.eof())

{
letter = input_file.get();
cout << letter;
}
}

ПРОВЕРКА ОШИБОК ПРИ ВЫПОЛНЕНИИ ФАЙЛОВЫХ ОПЕРАЦИЙ

Программы, представленные до настоящего момента, предполагали, что во время файловых операций В/В не происходят ошибки. К сожалению, это сбывается не всегда. Например, если вы открываете файл для ввода, ваши программы должны проверить, что файл существует. Аналогично, если ваша программа пишет данные в файл, вам необходимо убедиться, что операция прошла успешно (к примеру, отсутствие места на диске, скорее всего, помешает записи данных). Чтобы помочь вашим программам следить за ошибками, вы можете использовать функцию fail файлового объекта. Если в процессе файловой операции ошибок не было, функция возвратит ложь (0). Однако, если встретилась ошибка, функция fail возвратит истину. Например, если программа открывает файл, ей следует использовать функцию fail, чтобы определить, произошла ли ошибка, как это показано ниже:

ifstream input_file(«FILENAME.DAT»);
if (input_file.fail())

{
cerr << «Ошибка открытия FILENAME.EXT» << endl;
exit(1);
}

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

#include <iostream.h>

#include <fstream.h>

void main(void)

{
char line[256] ;
ifstream input_file(«BOOKINFO.DAT») ;
if (input_file.fail()) cerr << «Ошибка открытия BOOKINFO.DAT» << endl;
else

{
while ((! input_file.eof()) && (! input_file.fail()))

{
input_file.getline(line, sizeof(line)) ;
if (! input_file.fail()) cout << line << endl;
}
}
}

ЗАКРЫТИЕ ФАЙЛА, ЕСЛИ ОН БОЛЬШЕ НЕ НУЖЕН

При завершении вашей программы операционная система закроет открытые ею файлы. Однако, как правило, если вашей программе файл больше не нужен, она должна его закрыть. Для закрытия файла ваша программа должна использовать функцию close, как показано ниже:

input_file.close ();

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

УПРАВЛЕНИЕ ОТКРЫТИЕМ ФАЙЛА

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

ifstream output_file(«FILENAME.EXT», ios::app);

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

Таблица 34. Значения режимов открытия.

Режим открытия Назначение
ios::app Открывает файл в режиме добавления, располагая файловый указатель в конце файла.
ios::ate Располагает файловый указатель в конце файла.
ios::in Указывает открыть файл для ввода .
ios::nocreate Если указанный файл не существует, не создавать файл и возвратить ошибку. 
ios::noreplace Если файл существует, операция открытия должна быть прервана и должна возвратить ошибку.
ios::out Указывает открыть файл для вывода.
ios::trunc Сбрасывает (перезаписывает) содержим, з существующего файла.

Следующая операция открытия файла открывает файл для вывода, используя режим ios::noreplace, чтобы предотвратить перезапись существующего файла:

ifstream output_file(«FIlename.EXT», ios::out | ios::noreplace);

ВЫПОЛНЕНИЕ ОПЕРАЦИЙ ЧТЕНИЯ И ЗАПИСИ

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

input_file.read(buffer, sizeof(buffer)) ;
output_file.write(buffer, sizeof(buffer));

Например, следующая программа STRU_OUT.CPP использует функциюwrite для вывода содержимого структуры в файл EMPLOYEE.DAT:

#include <iostream.h>

#include <fstream.h>

void main(void)

{
struct employee

{
char name[64];
int age;
float salary;
} worker = { «Джон Дой», 33, 25000.0 };

ofstream emp_file(«EMPLOYEE.DAT») ;
emp_file.write((char *) &worker, sizeof(employee));
}

Функция write обычно получает указатель на символьную строку. Символы (char *) представляют собой оператор приведения типов, который информирует компилятор, что вы передаете указатель на другой тип. Подобным образом следующая программа STRU_IN.CPP использует метод read для чтения из файла информации о служащем:

#include <iostream.h>

#include <fstream.h>

void main(void)

{
struct employee

{
char name [6 4] ;
int age;
float salary;
} worker = { «Джон Дой», 33, 25000.0 };

ifstream emp_file(«EMPLOYEE.DAT»);
emp_file.read((char *) &worker, sizeof(employee));
cout << worker.name << endl;
cout << worker.age << endl;
cout << worker.salary << endl;
}

ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ

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

  1. Заголовочный файл fstream.h определяет классы ifstream иofstream, с помощью которых ваша программа может выполнять операции файлового ввода и вывода.
  2. Для открытия файла на ввод или вывод вы должны объявить объект типа ifstream или ofstream, передавая конструктору этого объекта имя требуемого файла.
  3. После того как ваша программа открыла файл для ввода или вывода, она может читать или писать данные, используя операторы извлечения (>>) и вставки (<<).
  4. Ваши программы могут выполнять ввод или вывод символов в файл или из файла, используя функции get и put.
  5. Ваши программы могут читать из файла целую строку, используя функцию getline.
  6. Большинство программ читают содержимое файла, пока не встретится конец файла. Ваши программы могут определить конец файла с помощью функции eof.
  7. Когда ваши программы выполняют файловые операции, они должны проверять состояние всех операций, чтобы убедиться, что операции выполнены успешно. Для проверки ошибок ваши программы могут использовать функцию fail.
  8. Если вашим программам необходимо вводить или выводить такие данные, как структуры или массивы, они могут использовать методы read и write.
  9. Если ваша программа завершила работу с файлом, его следует закрыть с помощью функции close.

Предыдущий урок | Следующий урок

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

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

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

Текстовый файл можно рассматривать как набор строк произвольной длины, разделенных управляющим символом 'n'. Логически текстовый файл представляет собой цепочку байт, имеющую начало и конец. Чтение (или запись) из файла (в файл) ведется байт за байтом от начала к концу.

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

Мы можем перенаправлять потоки в файлы. Такой механизм поддерживается уже на уровне операционной системы.

2.1 Работа с файлами в Си

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

FILE *handler;

После этого к файлу можно применять специальные функции:

  1. fscanf/fprintf используются для форматированного ввода/вывода при работе с текстовыми файлами. Описаны эти функции с библиотеке stdio.h (cstdio) и являются аналогами функций scanf и printf, которые, в свою очередь используются для ввода с клавиатуры и вывода на экран;
  2. fread/fwrite для чтения/записи бинарных файлов

2.2 Работа с файлами и потоками в C++

Существует четыре стандартных потока: cout, cerr, clog для вывода, и cin для ввода. Чтобы работать с потоками, нужно включить заголовочный файл iostream. Так что для любого консольного приложения, нужно добавить следующую строчку:

Частью стандартной библиотеки С++ является библиотека iostream, которая реализована как иерархия классов и обеспечивает базовые возможности ввода/вывода. Ввод с клавиатуры, называемый стандартным вводом, “привязан” к предопределенному объекту cin. Вывод на монитор, или стандартный вывод, привязан к объекту cout. Основным отличием файлового ввод/вывода является то, что ввод/вывод выполнятся не с клавиатуры и на экран, а из файла и в файл. Для организации файлового ввода/вывода достаточно создать собственные объекты, которые можно использовать аналогично cin и cout. Для работы с файлами с использованием потокового ввода-вывода необходимо подключить заголовочный файл <fstream>. В этом файле определены несколько классов и подключены заголовочные файлы – файловый ввод и <ofstream> – файловый вывод.

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

создать объект класса ofstream;
связать этот объект с файлом, в который будет производиться запись;
записать строку в файл;
закрыть файл.
Например, создаём объект fout для записи в файл:

ofstream out ; // объект класса ofstream

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

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

Указанный файл будет создан в текущей директории. Если файл с таким именем существует, то существующий файл будет заменен новым. Итак, файл открыт, записываем в него нужную строку:

out << "Скоро Новый год!"; // запись строки в файл

Так как больше нет необходимости изменять содержимое файла, его нужно закрыть, то есть отделить объект от файла.

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

Шаги по созданию объекта и связыванию его с файлом можно объединить:

ofstream out("out.txt.txt");

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

#include 

using namespace std;

int main( )
{
    ofstream out("out.txt"); // создаём объект 
    out << " Скоро Новый год!"; // запись строки в файл
    out.close(); // закрываем файл
    system("pause");
    return 0;
}

При считывании данных из файла может произойти ситуация достижения конца файла (end of file, сокращенно EOF). После достижения конца файла никакое чтение из файла невозможно. Для того чтобы проверить состояние файла, необходимо вызвать метод eof(). Данный метод возвращает true, если конец файла достигнут или false, если не достигнут. Например, в файле в текстовом файле File.txt хранится последовательность целых чисел, необходимо их считать и найти сумму:

    ifstream in;
    in.open("C:\File.txt");
    int k; int s = 0;
    while (!in.eof()) 
    { 
        in >> k;
        s= s+k;
    }

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

	ifstream in("C:\File.txt");
	int k; int s = 0;
	while (in >> k)
		s= s+k;

Организацию считывания файла построчно (считая, что строка заканчивается символом перехода на новую строку) продемонстрируем на примере кодирования файла путем замены кода символа следующим кодом из таблицы ASCII :

#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;

int main()
{
	ifstream in("C:\in.txt");
	ofstream out;
	out.open("C:\out.txt");
	char line[255];//Буферная переменная
	int c;
	if (!in.is_open()) // если файл не открыт
		cout << "Файл не найден!n"; // сообщить об этом
	else
	{
		while (in.getline(line, 255)) // считали строку 
		{
			for (c = 0;c < strlen(line); c++)
				if (line[c] == 255) 
					line[c] = 0;
				else 
					line[c] = line[c]+1;
			out << line << endl;
		}
		out.close();
	}
 }

Пример входного файла

До этого мы уже затрагивали тему ввода-вывода, но раньше данные считывались с клавиатуры и выводились в консоль. Теперь мы поговорим о чтении данных с файлов и вывода в такие же файлы. Мы тут не будем говорить о работе со структурой FILE (как это делалось в языке Си), речь пойдет о файловых потоках:

  1. Стандартный поток ввода — stdin;
  2. Стандартный поток вывода — stdout;
  3. Стандартный поток ошибок, этакий error_log — stderr;

Начнем с практики — программа считывающая из input.txt и записывающая в output.txt:

 #include <iostream>
 #include <cstdlib>
 #include <cstdio>
 // две новые библиотеки, нужны для работы freopen
 using namespace std;
 int d[1000000], n;
 /*
 переменные, инициализированные до функции main, 
 считаются глобальными т.е. изначально равны нулю и
 могут быть вызваны в любой части программы.
 Рекомендую создавать массивы глобальными всегда.
 */
 int sum (int l, int r) {
    int ans = 0;
    n = r - l + 1;
    for (int i = l, j = 1; i <= r; ++i, ++j)
     d[j] = i;
    for (int i = 1; i <= n; ++i)
     ans += d[i];
    return ans;
 }
 int main() {
     freopen ("input.txt", "r", stdin);
     freopen ("output.txt", "w", stdout);

     int a, b;
     cin >> a >> b;
     cout << sum (a, b) << "n";
     for (int i = 1; i <= n; ++i)
      cout << d[i] << " ";
     return 0;
 }

В этом примере работа с файлами идет через стандартные потоки ввода/вывода, но для того, чтобы перенаправить их в файл используется функция freopen. Константы "r" и "w" задают режимы работы с файлом. Всего есть 6 режимов:

1) Считывание, или «r», от слова read. Используется для потока ввода. Для считывания файл должен существовать.
2) Запись, или «w», от английского write. Используется для потока вывода. Если файла не существует, то он будет создан, иначе — перезаписан.
3) Добавление, или «a», от слова append. Используется для вывода, отличается от «w» тем, что продолжает записывать в файл, а не очищает его.
4,5,6) Те же моды, с разницей в том, что их можно использовать и для ввода, и для вывода. Вот сами моды «r+», «w+», «a+».

Так же для считывания можно использовать функции ifstream и ofstream, которые находятся в библиотеке <fstream>.

ifstream считывает с заданного файла. ofstream выводит в заданный файл.
Теперь о том как их написать:
ifstream название_функции_ввода («название_файла_ввода»);
ofstream название_функции_вывода («название_файла_вывода»);

Пример той же программы с использованием функций библиотеки fstream:

#include <fstream>
 using namespace std;
 int d[1000000], n;
 int sum (int l, int r)
 {
    int ans = 0;
    n = r - l + 1;
    for (int i = l, j = 1; i <= r; ++i, ++j)
     d[j] = i;
    for (int i = 1; i <= n; ++i)
     ans += d[i];
    return ans;
 }
 int main()
 {
     ifstream read_file ("input.txt");
     ofstream write_file ("output.txt");
     /*
        для считывания с файла input.txt мы будем 
        использовать функцию read_file, 
        можете заменить ее на что-нибудь другое
     */
     int a, b;
     read_file >> a >> b;
     write_file << sum (a, b) << "n";
     for (int i = 1; i <= n; ++i)
      write_file << d[i] << " ";
     return 0;
 }

Стоит отметить, что ifstream использует режим «a», а ofstream — режим «w». Можно открыть сколько угодно файлов, главное дать уникальное имя для функций ввода.

Для закрытия считывания или записи используйте функцию .close():

имя_функции_ввода/вывода.close();

Понравилась статья? Поделить с друзьями:
  • Какой документ должен прилагаться к производственной инструкции
  • Какой датой утверждается должностная инструкция
  • Какой вид списка вы используете для написания инструкции
  • Какой бензин заливать в двигатель 3s fe по инструкции
  • Какое значение возвращают инструкции прерывания цикла итерации в js