Сайт о телевидении

Сайт о телевидении

» » Чтение и запись в файл си. Ввод данных из файла и вывод в файл

Чтение и запись в файл си. Ввод данных из файла и вывод в файл

До этого при вводе-выводе данных мы работали со стандартными потоками - клавиатурой и монитором. Теперь рассмотрим, как в языке 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. Напишите программу, которая записывает в файл данные, полученные из другого файла и так или иначе измененные перед записью. Каждая строка данных, полученная из файла, должна помещаться в структуру.

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

Когда поток открывается для ввода-вывода, он связывается со стандартной структурой типа FILE, которая определена в stdio.h. Структура FILE содержит необходимую информацию о файле.

Открытие файла осуществляется с помощью функции fopen(), которая возвращается указатель на структуру типа FILE, который можно использовать для последующих операций с файлом.

FILE *fopen (name, type);

name – имя открываемого файла (включая путь),
type - указатель на строку символов, определяющих способ доступа к файлу:

· "r" - открыть файл для чтения (файл должен существовать);

· "w" - открыть пустой файл для записи; если файл существует, то его содержимое теряется;

· "a" - открыть файл для записи в конец (для добавления); файл создается, если он не существует;

· "r+" - открыть файл для чтения и записи (файл должен существовать);

· "w+" - открыть пустой файл для чтения и записи; если файл существует, то его содержимое теряется;

· "a+" - открыть файл для чтения и дополнения, если файл не существует, то он создаётся.

Возвращаемое значение - указатель на открытый поток. Если обнаружена ошибка, то возвращается значение NULL.

Функция fclose() закрывает поток или потоки, связанные с открытыми при помощи функции fopen() файлами. Закрываемый поток определяется аргументом функции fclose().

Возвращаемое значение: значение 0, если поток успешно закрыт; константа EOF, если произошла ошибка.

#include
int main()

char name="my.txt";

if(fp = fopen(name, "r")!=NULL)

// открыть файлу далось?
... // требуемые действия над данными

else printf("Не удалось открыть файл");

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

char fgetc(поток);

Аргументом функции является указатель на поток типа FILE. Функция возвращает код считанного символа. Если достигнут конец файла или возникла ошибка, возвращается константа EOF.
Запись символа в файл :

fputc(символ,поток);

Аргументами функции являются символ и указатель на поток типа FILE. Функция возвращает код считанного символа.

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

fscanf(поток, "Формат Ввода", аргументы);
fprintf(поток, "Формат Вывода", аргументы);

Функции fgets() и fputs() предназначены для ввода-вывода строк, они являются аналогами функций gets() и puts() для работы с файлами.

fgets(Указатель На Строку, Количество Символов, поток);

Символы читаются из потока до тех пор, пока не будет прочитан символ новой строки "\n", который включается в строку, или пока не наступит конец потока EOF или не будет прочитано максимальное символов. Результат помещается в указатель на строку и заканчивается нуль- символом "\0". Функция возвращает адрес строки.

fputs(Указатель На Строку, поток);

Копирует строку в поток с текущей позиции. Завершающий нуль- символ не копируется.
Пример Ввести число и сохранить его в файле s1.txt. Считать число из файла s1.txt, увеличить его на 3 и сохранить в файле s2.txt.

Работа с текстовыми файлами в C++.

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

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

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

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

В программах на C++ при работе с текстовыми файлами необходимо подключать библиотеки iostream и fstream.

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

    описать переменную типа ofstream.

    вывести информацию в файл.

    обязательно закрыть файл.

Для считывания данных из текстового файла, необходимо:

    описать переменную типа ifstream.

    открыть файл с помощью функции open.

    закрыть файл.

Запись информации в текстовый файл

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

    Будет создана переменная F для записи информации в файл.

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

F.open(«file», mode);

Здесь F - переменная, описанная как ofstream,

file - полное имя файла на диске,

mode - режим работы с открываемым файлом.

Обратите внимание на то, что при указании полного имени файла нужно ставить двойной слеш. Например, полное имя файла noobs.txt, находящегося в папке game на диске D:, нужно будет записать так:

D:\\game\\noobs.txt.

Файл может быть открыт в одном из следующих режимов:

ios::in - открыть файл в режиме чтения данных, этот режим является режимом по умолчанию для потоков ifstream;

ios::out - открыть файл в режиме записи данных (при этом информация о существующем файле уничтожается), этот режим является режимом по умолчанию для потоков ofstream;

ios::app - открыть файл в режиме записи данных в конец файла;

ios::ate - передвинуться в конец уже открытого файла;

ios::trunc - очистить файл, это же происходит в режиме ios::out;

ios::nocreate - не выполнять операцию открытия файла, если он не существует;

ios::noreplace - не открывать существующий файл.

Параметр mode может отсутствовать, в этом случае файл открывается в режиме по умолчанию для данного потока.

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

Открыть файл (в качестве примера возьмем файл D:\\game\\noobs.txt) в режиме записи можно одним из следующих способов:

// первый способ

ofstream F;

F.open("D:\\game\\noobs.txt", ios::out);

//второй способ, режим ios::out является режимом по умолчанию

// для потока ofstream

ofstream F;

//третий способ объединяет описание переменной и типа поток

//и открытие файла в одном операторе

ofstream F ("D:\\game\\noobs.txt", ios::out);

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

Если вы хотите открыть существующий файл в режиме до записи, то в качестве режима следует использовать значение ios::app.

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

Например, для записи в поток F переменной a, оператор вывода будет иметь вид:

Для последовательного вывода в поток G переменных b, c, d оператор вывода станет таким:

G<

Закрытие потока осуществляется с помощью оператора:

ПРИМЕР:

Создать текстовый файл D:\\game\\noobs.txt и записать в него n вещественных чисел.

#include "stdafx.h"

#include

#include

#include

using namespace std;

int main()

setlocale (LC_ALL, "RUS");

int i, n;

double a;

//описывает поток для записи данных в файл

ofstream f ;

//открываем файл в режиме записи,

//режим ios :: out устанавливается по умолчанию

f.open("D:\\game\\noobs.txt", ios::out);

//вводим количество вещественных чисел

cout <<" n ="; cin >> n ;

//цикл для ввода вещественных чисел

//и записи их в файл

for (i=0; i

cout<<"a=";

//ввод числа

cin>>a;

f<

//закрытие потока

f.close();

system("pause");

return 0;

_______________________________________________________________

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

F.open("D:\\game\\noobs.txt", ios::in);

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

Например, для чтения из потока F в переменную a, оператор ввода будет выглядеть так:

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

Здесь F - имя потока функция возвращает логическое значение: true или false, в зависимости от того достигнут ли конец файла. Следовательно, цикл для чтения содержимого всего файла можно записать так:

//организуем для чтения значений из файла, выполнение

//цикла прервется, когда достигнем конец файла,

//в этом случае F.eof() вернет истину

while (!F.eof())

ПРИМЕР:

В текстовом файле D:\\game\\noobs.txt хранятся вещественные числа, вывести их на экран и вычислить их количество.

#include "stdafx.h"

#include

#include

#include

#include

using namespace std;

int main()

setlocale (LC_ALL, "RUS");

int n=0;

float a;

fstream F;

//открываем файл в режиме чтения

F.open("D:\\game\\noobs.txt");

//если открытие файла прошло корректно, то

//цикл для чтения значений из файла; выполнение цикла прервется,

//когда достигнем конца файла, в этом случае F.eof() вернет истину.

while (!F.eof())

//чтение очередного значения из потока F в переменную a

F>>a;

//вывод значения переменной a на экран

cout<

//увеличение количества считанных чисел

//закрытие потока

F.close();

//вовод на экран количества считанных чисел

cout<<"n="<

//если открытие файла прошло некорректно, то вывод

//сообщения об отсутствии такого файла

else cout<<" Файл не существует"<

system("pause");

return 0;

C++. Обработка двоичных файлов

При записи информации в двоичный файл символы и числа записываются в виде последовательности байт.

Для того чтобы записать данные в двоичный файл, необходимо:

    описать файловую переменную типа FAIL * с помощью оператора FILE *filename;. Здесь filename - имя переменной, где будет храниться указатель на файл.

    записать информацию в файл с помощью функции fwrite

Для того чтобы считат ь данные из двоичного файла, необходимо:

    описать переменную типа FILE *

    открыть файл с помощью функции fopen

    закрыть файл с помощью функции fclose

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

Для открытия файла предназначена функция fopen.

FILE *fopen(const *filename, const char *mode)

Здесь filename - строка, в которой хранится полное имя открываемого файла, mode - строка, определяющая режим работы с файлом; возможны следующие значения:

«rb» - открываем двоичный файл в режиме чтения;

«wb» - создаем двоичный файл для записи; если он существует, то его содержимое очищается;

«ab» - создаем или открываем двоичный файл для дозаписи в конец файла;

«rb+» - открываем существующий двоичный файл в режиме чтения и записи;

«wb+» - открываем двоичный файл в режиме чтения и записи, существующий файл очищается;

«ab+» - двоичный файл открывается или создается для исправления существующий информации и добавления новой в конец файла.

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

Для закрытия файла предназначена функция fclose

int fclose(FILE *filename);

Возвращает 0 при успешном закрытие файла и NULL в противном случае.

Функция remove предназначена для удаления файлов.

int remove(const char *filename);

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

Для переименования файлов предназначена функция rename:

int rename(const char *oldfilename, const char *newfilename);

Первый параметр - старое имя файла, второй - новое. Возвращает 0 при удачном завершении программы.

Чтение из двоичного файла осуществляется с помощью функции fread:

fread(void *ptr, size, n, FILE *filename);

Функция fread считывает из файла filename в массив ptr n элементов размера size. Функция возвращает количество считанных элементов. После чтения из файла его указатель смещается на n*size байт.

Запись в двоичный файл осуществляется с помощью функции fwrite:

fwrite(const void *ptr, size, n, FILE *filename);

Функция fwrite записывает в файл filename из массива ptr n элементов размера size. Функция возвращает количество записанных элементов. После записи информации в файл указатель смещается на n*size байт.

Для контроля достижения конца файла есть функция feof:

int feof(FILE *filename);

Она возвращает ненулевое значение если достигнут конец файла.

ПРИМЕР:

Создать двоичный файл D:\\game\\noobs.dat и записать в него целое число n и n вещественных чисел.

#include "stdafx.h"

#include

using namespace std;

int main()

setlocale (LC_ALL, "RUS");

int n, i;

double a;

//создаем двоичный файл в режиме записи

f=fopen("D:\\game\\noobs.dat", "wb");

// ввод числа n

cout<<"n="; cin>>n;

fwrite(&n, sizeof(int), 1, f);

//цикл для ввода n вещественных чисел

for (i=0; i

//ввод очередного вещественного числа

cout<<"a=";

cin>>a;

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

fwrite(&a, sizeof(double), 1, f);

// закрываем файл

fclose(f);

system("pause");

return 0;

ПРИМЕР:

Вывести на экран содержимого созданного в прошлой задаче двоичного файла D:\\game\\noobs.dat

#include "stdafx.h"

#include

using namespace std;

int main()

setlocale (LC_ALL, "RUS");

int n, i;

double *a;

FILE *f; //описываем файловую переменную

//открываем существующий двоичный файл в режиме чтения

//считываем из файла одно целое число в переменную n

//вывод n на экран

cout<<"n="<

//выделение памяти для массива из n чисел

a=new double[n];

//чтение n вещественных чисел из файла в массив a

//вывод массива на экран

for (i=0; i

cout<

cout<

// закрываем файл

fclose(f);

system("pause");

return 0;

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

int n, i;

double a;

FILE *f;

f=fopen("D:\\game\\noobs.dat", "rb");

for (i=0; i<15; i++)

fclose(f);

f=fopen("D:\\game\\noobs.dat", "rb");

fread(&a, sizeof(double), 1, f);

fclose(f);

Как видно, такое чтение чисел из файла, а затем повторное открытие файла - не самый удобный способ. Гораздо удобнее будет использовать функцию fseek перемещения указателя файла к заданному байту.

int fseek(FILE *filename, long int offset, int origin);

Функция устанавливает указатель текущий позиции файла F в соответствии со значением начала отсчета origin и смещения offset. Параметр offset равен количеству байтов, на которые будет смещен указатель файла относительно начала отсчета, заданного параметром origin. В качестве значения для параметра origin должно быть взято одно из следующих значений отсчета смещения offset, определенных в заголовке stdio.h:

SEEK_SET - с начала файла;

SEEK_CUR - с текущей позиции;

SEEK_END - с конца файла.

Функция возвращает нулевое значение при успешном выполнение операции, ненулевое - при возникновении сбоя при выполнении смещения

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

ПРИМЕР

В созданном раннее двоичном файле D:\\game\\noobs.dat, поменять местами наибольшее и наименьшее из вещественных чисел.

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

    чтение вещественных из файла в массив a.

    поиск в массиве а максимального (max) и минимального (min) значения и их номеров (imax, imin).

    перемещения указателя файла к максимальному значению и запись min.

    перемещения указателя файла к минимальному значению и запись max.

Ниже приведен текст программы решения задачи с комментариями.

#include "stdafx.h"

#include

using namespace std;

int main()

setlocale (LC_ALL, "RUS");

int n, i, imax, imin;

double *a, max, min;

FILE *f;

//открытие файла в режиме чтения и записи

f=fopen("D:\\game\\noobs.dat", "rb+");

//считываем из файла в переменную n количество

//вещественных чисел в файле

fread(&n, sizeof(int), 1, f);

cout<<"n="<

//выделяем память для хранения вещественных чисел,

//которые будут храниться в массиве a

a=new double[n];

//считываем из файла в массив а вещественные числа

fread(a, sizeof(double), n, f);

//поиск максимального и минимального элементов

//в массиве а и их индексов

for (imax=imin=0, max=min=a, i=1; i

if (a[i]>max)

max=a[i];

if (a[i]

min=a[i];

// перемещение указателя к максимальному элементу

fseek(f, sizeof(int)+imax*sizeof(double), SEEK_SET);

//запись min вместо максимального элемента файла

fwrite(&min, sizeof(double), 1, f);

// перемещение указателя к минимальному элементу

fseek(f, sizeof(int)+imin*sizeof(double), SEEK_SET);

//запись max вместо минимального элемента файла

fwrite(&max, sizeof(double), 1, f);

//закрытие файла

fclose(f);

//освобождение памяти

delete [ ]a;

system("pause");

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

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

#include

int main ()
{
char s1 // Переменная будет считывать строку
ifstream in (“C:\\\FromC\\myfile.txt” ); // Открываем файл для считывания информации
in >>s1 ; // считываем строку
in .close () // Закрываем файл

cout <Выводим значение s1 на экран
return 0 ;
}

Вот наипростейшая программа для считывания первой строки из текстового файла, который находится по пути
C:\\\FromC\\myfile.txt –
Так как это продолжение прошлой статьи , то я решил использовать тот файл, который мы там создавали. Трудностей с этим, наверное возникнуть не должно.
Но вернемся к коду. Сначала мы открываем файл для считывания из него информации, для этого используем команду ifstream , в скобках указываем либо название файла, либо путь к файлу, как сделано у меня.(“C:\\\FromC\\myfile.txt” );
Когда мы открыли файл, чтобы считать из него что-то, мы объявили одну переменную типа char –
char s1
Теперь нам осталось только присвоить переменной значение строки из файла. Это мы делаем командой in
Обращаем внимание на угловые скобки in >>
Собственно, как должно быть видно из комментариев к коду программы, то чтобы переменная присвоила считываемое значение, мы должны написать её после in >>
in >>s1 ;

Никакой особо сложной задачей это не представляется, особенно если вы уже прекрасно освоили и научились использовать материал прошлой статьи – всё абсолютно аналогично, только 2 команды другие

Создание файла и запись в него информации С++

ofstream out (Имя файла );
out << (Записываемая строка );
out .close ();
=============================

Чтение текста из файла и вывода текста на экран в C++

ifstream in (Имя файла );
in >> (Считываем строку );
in .close (); (Закрываем файл )
============================
Напишем простую программу, которая будет считывать ввод с клавиатуры текста и записывать его в файл:

#include
#include

int main ()
{
\\ 3 будущие строки
clrscsr (); // Очищаем экран

cout <<“Wwedi pervuu stroku” ; cin >>a ; endl ;
cout <<“Wwedi wtoruu stroku” ; cin >>b ; endl ;
cout <<“Wwedi tretuu stroku” ; cin >>c ; endl ;
clrscr (); //

/*Начинаем работу с файлом*/
ofstream out (“C:\\\FromC\\myfile.txt” ); // Открываем файл для записи
out <Записываем первую строчку
out <Записываем вторую строчку
out <Записываем третью строчку
out .close (); // Закрываем файл

//Обнуляем переменные

for (int i =0 ;i <=255 ;i ++)
{a =*“” ; b =*“” ; c =*“” ;}


ifstream in (“C:\\\FromC\\myfile.txt” );
in >>a >>b >>c ; // Считываем каждую новую строчку в новую переменную
in .close (); // Закрываем файл

/* */

for (i =0 ;a !=*“” ;i ++)
{
if (i >sizeof(a )) break ;
cout <

}
cout <<“\n” ; \\

/* */


{
if (i >sizeof(b )) break ;
cout <
}
cout <<“\n” ; \\ Перевели курсор на новую строчку

/* */

for (i =0 ;с !=*“” ;i ++)
{
if (i >sizeof(c )) break ;
cout <<с ;
}

return 0 ;
}
===================

В приведенных выше примерах есть один такой ОГРОМНЫЙ недостаток. Если мы будем пытаться ввести строчку, содержащую пробелы, то программа будет срабатывать не так как нам нужно. Наверное, на эту ошибку наткнулся не только я, но и многие другие люди. Поэтому я оставляю неверно приведенный код, чтобы было видно с чем можно столкнуться.

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

#include
#include

int main ()
{
char a ,b ,c ; \\ 3 будущие строки
clrscsr (); // Очищаем экран

/* Вводим значения для переменных*/

cout <<“Wwedi pervuu stroku” ; cin.getline(a,sizeof(a)); endl ;
cout <<“Wwedi wtoruu stroku” ; cin.getline(a,sizeof(b)); endl ;
cout <<“Wwedi tretuu stroku” ; cin.getline(a,sizeof(c)); endl ;
clrscr (); // После ввода значений очистили экран

/*Начинаем работу с файлом*/
ofstream out (“C:\\\FromC\\myfile.txt”); // Открываем файл для записи
out <
Записываем первую строчку
out <Записываем вторую строчку
out <Записываем третью строчку
out .close (); // Закрываем файл

//Обнуляем переменные

for (int i =0 ;i <=255 ;i ++)
{a =*“” ; b =*“” ; c=*“” ;}

/*Продолжаем работу с файлом*/

if stream in (“C:\\\FromC\\myfile.txt” );
in.getline(a,sizeof(a)); // а
in.getline(b,sizeof(b)); // Считываем строчку в переменную b
in.getline(c,sizeof(c)); // Считываем строчку в переменную c
in .close (); // Закрываем файл

/* Считываем посимвольно первую строку и выводим её на экран*/

for (i =0 ;a !=*“” ;i++)
{
if (i >sizeof(a )) break ;
cout <

}
cout <<“\n” ; \\ Перевели курсор на новую строчку

/* Считываем посимвольно вторую строку и выводим её на экран*/

for (i =0 ;b !=*“” ;i ++)
{
if (i >sizeof(b )) break ;
cout <
}
cout <<“\n” ; \\ Перевели курсор на новую строчку

/* Считываем посимвольно третью строку и выводим её на экран*/

for (i =0 ;с !=*“” ;i++)
{
if (i>sizeof (c )) break ;
cout <<с[i];
}

getch (); \\ Ожидаем нажатия клавиши Enter
return 0 ;
}
===================

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

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

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

Примечание:
break ; – Это команда, которая выполняет выход из цикла. У нас если счетчик цикла for становится больше чем объявленный размер переменной char, то мы принудительно выходим из цикла
!= – это поставленное нами условие. Обозначает такое условие неравенство
if(a !=b ) – Читается как если a не равно b

endl ; – Это перевод курсора на новую строку внутри консоли (насколько я понял)
Эта команда похожа на“\n”

Большинство компьютерных программ работают с файлами, и поэтому возникает необходимость создавать, удалять, записывать читать, открывать файлы. Что же такое файл? Файл – именованный набор байтов, который может быть сохранен на некотором накопителе. Ну, теперь ясно, что под файлом понимается некоторая последовательность байтов, которая имеет своё, уникальное имя, например файл.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 << "Работа с файлами в С++"; // запись строки в файл

Используя операцию передачи в поток совместно с объектом 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. закрыть файл.
// 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.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; }

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

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

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

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

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

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

Режимы открытия файлов можно устанавливать непосредственно при создании объекта или при вызове функции 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 #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 .