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

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

#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”

Теги: Текстовые файлы, fopen, fclose, feof, setbuf, setvbuf, fflush, fgetc, fprintf, fscanf, fgets, буферизированный поток, небуферизированный поток.

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

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

  • 1. Открыть файл, для того, чтобы к нему можно было обращаться. Соответственно, открывать можно для чтения, записи, чтения и записи, переписывания или записи в конец файла и т.п. Когда вы открываете файл, может также произойти куча ошибок – файла может не существовать, это может быть файл не того типа, у вас может не быть прав на работу с файлом и т.д. Всё это необходимо учитывать.
  • 2. Непосредственно работа с файлом - запись и чтение. Здесь также нужно помнить, что мы работаем не с памятью с произвольным доступом, а с буферизированным потоком, что добавляет свою специфику.
  • 3. Закрыть файл. Так как файл является внешним по отношению к программе ресурсом, то если его не закрыть, то он продолжит висеть в памяти, возможно, даже после закрытия программы (например, нельзя будет удалить открытый файл или внести изменения и т.п.). Кроме того, иногда необходимо не закрывать, а "переоткрывать" файл для того, чтобы, например, изменить режим доступа.

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

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

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

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

Создание и выделение памяти под объект типа FILE осуществляется с помощью функции fopen или tmpfile (есть и другие, но мы остановимся только на этих).

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

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

Например, откроем файл и запишем в него Hello World

#include #include #include void main() { //С помощью переменной file будем осуществлять доступ к файлу FILE *file; //Открываем текстовый файл с правами на запись file = fopen("C:/c/test.txt", "w+t"); //Пишем в файл fprintf(file, "Hello, World!"); //Закрываем файл fclose(file); getch(); }

Функция fopen сама выделяет память под объект, очистка проводится функцией fclose. Закрывать файл обязательно, самостоятельно он не закроется.

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

Параметры доступа к файлу.
Тип Описание
r Чтение. Файл должен существовать.
w Запись нового файла. Если файл с таким именем уже существует, то его содержимое будет потеряно.
a Запись в конец файла. Операции позиционирования (fseek, fsetpos, frewind) игнорируются. Файл создаётся, если не существовал.
r+ Чтение и обновление. Можно как читать, так и писать. Файл должен существовать.
w+ Запись и обновление. Создаётся новый файл. Если файл с таким именем уже существует, то его содержимое будет потеряно. Можно как писать, так и читать.
a+ Запись в конец и обновление. Операции позиционирования работают только для чтения, для записи игнорируются. Если файл не существовал, то будет создан новый.

Если необходимо открыть файл в бинарном режиме, то в конец строки добавляется буква b, например “rb”, “wb”, “ab”, или, для смешанного режима “ab+”, “wb+”, “ab+”. Вместо b можно добавлять букву t, тогда файл будет открываться в текстовом режиме. Это зависит от реализации. В новом стандарте си (2011) буква x означает, что функция fopen должна завершиться с ошибкой, если файл уже существует. Дополним нашу старую программу: заново откроем файл и считаем, что мы туда записали.

#include #include #include void main() { FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); fprintf(file, "Hello, World!"); fclose(file); file = fopen("C:/c/test.txt", "r"); fgets(buffer, 127, file); printf("%s", buffer); fclose(file); getch(); }

Вместо функции fgets можно было использовать fscanf, но нужно помнить, что она может считать строку только до первого пробела.
fscanf(file, "%127s", buffer);

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

#include #include #include void main() { FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); fprintf(file, "Hello, World!"); freopen("C:/c/test.txt", "r", file); fgets(buffer, 127, file); printf("%s", buffer); fclose(file); getch(); }

Функции fprintf и fscanf отличаются от printf и scanf только тем, что принимают в качестве первого аргумента указатель на FILE, в который они будут выводить или из которого они будут читать данные. Здесь стоит сразу же добавить, что функции printf и scanf могут быть без проблем заменены функциями fprintf и fscanf. В ОС (мы рассматриваем самые распространённые и адекватные операционные системы) существует три стандартных потока: стандартный поток вывода stdout, стандартный поток ввода stdin и стандартный поток вывода ошибок stderr. Они автоматически открываются во время запуска приложения и связаны с консолью. Пример

#include #include #include void main() { int a, b; fprintf(stdout, "Enter two numbers\n"); fscanf(stdin, "%d", &a); fscanf(stdin, "%d", &b); if (b == 0) { fprintf(stderr, "Error: divide by zero"); } else { fprintf(stdout, "%.3f", (float) a / (float) b); } getch(); }

Ошибка открытия файла

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

#include #include #include #define ERROR_OPEN_FILE -3 void main() { FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); if (file == NULL) { printf("Error opening file"); getch(); exit(ERROR_OPEN_FILE); } fprintf(file, "Hello, World!"); freopen("C:/c/test.txt", "r", file); if (file == NULL) { printf("Error opening file"); getch(); exit(ERROR_OPEN_FILE); } fgets(buffer, 127, file); printf("%s", buffer); fclose(file); getch(); }

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

FILE *inputFile, *outputFile; unsigned m, n; unsigned i, j; inputFile = fopen(INPUT_FILE, READ_ONLY); if (inputFile == NULL) { printf("Error opening file %s", INPUT_FILE); getch(); exit(3); } outputFile = fopen(OUTPUT_FILE, WRITE_ONLY); if (outputFile == NULL) { printf("Error opening file %s", OUTPUT_FILE); getch(); if (inputFile != NULL) { fclose(inputFile); } exit(4); } ...

В простых случаях можно действовать влоб, как в предыдущем куске кода. В более сложных случаях используются методы, подменяющиее RAII из С++: обёртки, или особенности компилятора (cleanup в GCC) и т.п.

Буферизация данных

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

  • 1) Если он заполнен
  • 2) Если поток закрывается
  • 3) Если мы явно указываем, что необходимо очистить буфер (здесь тоже есть исключения:)).
  • 4) Также очищается, если программа завершилась удачно. Вместе с этим закрываются и все файлы. В случае ошибки выполнения этого может не произойти.

Форсировать выгрузку буфера можно с помощью вызова функции fflush(File *). Рассмотрим два примера – с очисткой и без.

#include #include #include void main() { FILE *file; char c; file = fopen("C:/c/test.txt", "w"); do { c = getch(); fprintf(file, "%c", c); fprintf(stdout, "%c", c); //fflush(file); } while(c != "q"); fclose(file); getch(); }

Раскомментируйте вызов fflush. Во время выполнения откройте текстовый файл и посмотрите на поведение.

Буфер файла можно назначить самостоятельно, задав свой размер. Делается это при помощи функции

Void setbuf (FILE * stream, char * buffer);

которая принимает уже открытый FILE и указатель на новый буфер. Размер нового буфера должен быть не меньше чем BUFSIZ (к примеру, на текущей рабочей станции BUFSIZ равен 512 байт). Если передать в качестве буфера NULL, то поток станет небуферизированным. Можно также воспользоваться функцией

Int setvbuf (FILE * stream, char * buffer, int mode, size_t size);

которая принимает буфер произвольного размера size. Режим mode может принимать следующие значения

  • _IOFBF - полная буферизация. Данные записываются в файл, когда он заполняется. На считывание, буфер считается заполненным, когда запрашивается операция ввода и буфер пуст.
  • _IOLBF - линейная буферизация. Данные записываются в файл когда он заполняется, либо когда встречается символ новой строки. На считывание, буфер заполняется до символа новой строки, когда запрашивается операция ввода и буфер пуст.
  • _IONBF – без буферизации. В этом случае параметры size и buffer игнорируются.
В случае удачного выполнения функция возвращает 0.

Пример: зададим свой буфер и посмотрим, как осуществляется чтение из файла. Пусть файл короткий (что-нибудь, типа Hello, World!), и считываем мы его посимвольно

#include #include #include void main() { FILE *input = NULL; char c; char buffer = {0}; input = fopen("D:/c/text.txt", "rt"); setbuf(input, buffer); while (!feof(input)) { c = fgetc(input); printf("%c\n", c); printf("%s\n", buffer); _getch(); } fclose(input); }

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

feof

Функция int feof (FILE * stream); возвращает истину, если конец файла достигнут. Функцию удобно использовать, когда необходимо пройти весь файл от начала до конца. Пусть есть файл с текстовым содержимым text.txt. Считаем посимвольно файл и выведем на экран.

#include #include #include void main() { FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) { printf("Error opening file"); _getch(); exit(0); } while (!feof(input)) { c = fgetc(input); fprintf(stdout, "%c", c); } fclose(input); _getch(); }

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

#include #include #include void main() { FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) { printf("Error opening file"); _getch(); exit(0); } while (!feof(input)) { fscanf(input, "%c", &c); fprintf(stdout, "%c", c); } fclose(input); _getch(); }

Этот пример сработает с ошибкой (скорее всего) и выведет последний символ файла два раза.

Решение – не использовать feof. Например, хранить общее количество записей или использовать тот факт, что функции fscanf и пр. обычно возвращают число верно считанных и сопоставленных значений.

#include #include #include void main() { FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) { printf("Error opening file"); _getch(); exit(0); } while (fscanf(input, "%c", &c) == 1) { fprintf(stdout, "%c", c); } fclose(input); _getch(); }

Примеры

1. В одном файле записаны два числа - размерности массива. Заполним второй файл массивом случайных чисел.

#include #include #include #include //Имена файлов и права доступа #define INPUT_FILE "D:/c/input.txt" #define OUTPUT_FILE "D:/c/output.txt" #define READ_ONLY "r" #define WRITE_ONLY "w" //Максимальное значение для размера массива #define MAX_DIMENSION 100 //Ошибка при открытии файла #define ERROR_OPEN_FILE -3 void main() { FILE *inputFile, *outputFile; unsigned m, n; unsigned i, j; inputFile = fopen(INPUT_FILE, READ_ONLY); if (inputFile == NULL) { printf("Error opening file %s", INPUT_FILE); getch(); exit(ERROR_OPEN_FILE); } outputFile = fopen(OUTPUT_FILE, WRITE_ONLY); if (outputFile == NULL) { printf("Error opening file %s", OUTPUT_FILE); getch(); //Если файл для чтения удалось открыть, то его необходимо закрыть if (inputFile != NULL) { fclose(inputFile); } exit(ERROR_OPEN_FILE); } fscanf(inputFile, "%ud %ud", &m, &n); if (m > MAX_DIMENSION) { m = MAX_DIMENSION; } if (n > MAX_DIMENSION) { n = MAX_DIMENSION; } srand(time(NULL)); for (i = 0; i < n; i++) { for (j = 0; j < m; j++) { fprintf(outputFile, "%8d ", rand()); } fprintf(outputFile, "\n"); } //Закрываем файлы fclose(inputFile); fclose(outputFile); }

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

#include #include #include #define ERROR_FILE_OPEN -3 void main() { FILE *origin = NULL; FILE *output = NULL; char filename; int mode; printf("Enter filename: "); scanf("%1023s", filename); origin = fopen(filename, "r"); if (origin == NULL) { printf("Error opening file %s", filename); getch(); exit(ERROR_FILE_OPEN); } printf("enter mode: "); scanf("%d", &mode); if (mode == 1) { printf("Enter filename: "); scanf("%1023s", filename); output = fopen(filename, "w"); if (output == NULL) { printf("Error opening file %s", filename); getch(); fclose(origin); exit(ERROR_FILE_OPEN); } } else { output = stdout; } while (!feof(origin)) { fprintf(output, "%c", fgetc(origin)); } fclose(origin); fclose(output); getch(); }

3. Пользователь вводит данные с консоли и они записываются в файл до тех пор, пока не будет нажата клавиша esc. Проверьте программу и посмотрите. как она себя ведёт в случае, если вы вводите backspace: что выводится в файл и что выводится на консоль.

#include #include #include #define ERROR_FILE_OPEN -3 void main() { FILE *output = NULL; char c; output = fopen("D:/c/test_output.txt", "w+t"); if (output == NULL) { printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); } for (;;) { c = _getch(); if (c == 27) { break; } fputc(c, output); fputc(c, stdout); } fclose(output); }

4. В файле записаны целые числа. Найти максимальное из них. Воспользуемся тем, что функция fscanf возвращает число верно прочитанных и сопоставленных объектов. Каждый раз должно возвращаться число 1.

#include #include #include #define ERROR_FILE_OPEN -3 void main() { FILE *input = NULL; int num, maxn, hasRead; input = fopen("D:/c/input.txt", "r"); if (input == NULL) { printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); } maxn = INT_MIN; hasRead = 1; while (hasRead == 1) { hasRead = fscanf(input, "%d", &num); if (hasRead != 1) { continue; } if (num >

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

#include #include #include #include #define ERROR_FILE_OPEN -3 void main() { FILE *input = NULL; int num, maxn, hasRead; input = fopen("D:/c/input.txt", "r"); if (input == NULL) { printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); } maxn = INT_MIN; while (!feof(input)) { fscanf(input, "%d", &num); if (num > maxn) { maxn = num; } } printf("max number = %d", maxn); fclose(input); _getch(); }

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

Файл с переводом выглядит примерно так

Солнце sun
карандаш pen
шариковая ручка pencil
дверь door
окно windows
стул chair
кресло armchair

и сохранён в кодировке cp866 (OEM 866). При этом важно: последняя пара cлов также заканчивается переводом строки.

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

#include #include #include #include #define ERROR_FILE_OPEN -3 void main() { FILE *input = NULL; char buffer; char enWord; char ruWord; char usrWord; unsigned index; int length; int wasFound; input = fopen("D:/c/input.txt", "r"); if (input == NULL) { printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); } printf("enter word: "); fgets(usrWord, 127, stdin); wasFound = 0; while (!feof(input)) { fgets(buffer, 511, input); length = strlen(buffer); for (index = 0; index < length; index++) { if (buffer == "\t") { buffer = "\0"; break; } } strcpy(ruWord, buffer); strcpy(enWord, &buffer); if (!strcmp(enWord, usrWord)) { wasFound = 1; break; } } if (wasFound) { printf("%s", ruWord); } else { printf("Word not found"); } fclose(input); _getch(); }

6. Подсчитать количество строк в файле. Будем считывать файл посимвольно, считая количество символов "\n" до тех пор, пока не встретим символ EOF. EOF - это спецсимвол, который указывает на то, что ввод закончен и больше нет данных для чтения. Функция возвращает отрицательное значение в случае ошибки.
ЗАМЕЧАНИЕ: EOF имеет тип int, поэтому нужно использовать int для считывания символов. Кроме того, значение EOF не определено стандартом.

#define _CRT_SECURE_NO_WARNINGS #include #include #include int cntLines(const char *filename) { int lines = 0; int any; //any типа int, потому что EOF имеет тип int! FILE *f = fopen(filename, "r"); if (f == NULL) { return -1; } do { any = fgetc(f); //printf("%c", any);//debug if (any == "\n") { lines++; } } while(any != EOF); fclose(f); return lines; } void main() { printf("%d\n", cntLines("C:/c/file.txt")); _getch(); }

Ru-Cyrl 18- tutorial Sypachev S.S. 1989-04-14 [email protected] Stepan Sypachev students

Всё ещё не понятно? – пиши вопросы на ящик

Для удобства обращения информация в запоминающих устройствах хранится в виде файлов.

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

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

Файловой системой называется функциональная часть операционной системы, обеспечивающая выполнение операций над файлами. Примерами файловых систем являются FAT (FAT – File Allocation Table, таблица размещения файлов), NTFS, UDF (используется на компакт-дисках).

Существуют три основные версии FAT: FAT12, FAT16 и FAT32. Они отличаются разрядностью записей в дисковой структуре, т.е. количеством бит, отведённых для хранения номера кластера. FAT12 применяется в основном для дискет (до 4 кбайт), FAT16 – для дисков малого объёма, FAT32 – для FLASH-накопителей большой емкости (до 32 Гбайт).

Рассмотрим структуру файловой системы на примере FAT32.

Файловая структура FAT32

Устройства внешней памяти в системе FAT32 имеют не байтовую, а блочную адресацию. Запись информации в устройство внешней памяти осуществляется блоками или секторами.

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

Кластер – объединение нескольких секторов, которое может рассматриваться как самостоятельная единица, обладающая определёнными свойствами. Основным свойством кластера является его размер, измеряемый в количестве секторов или количестве байт.

Файловая система FAT32 имеет следующую структуру.

Нумерация кластеров, используемых для записи файлов, ведется с 2. Как правило, кластер №2 используется корневым каталогом, а начиная с кластера №3 хранится массив данных. Сектора, используемые для хранения информации, представленной выше корневого каталога, в кластеры не объединяются.
Минимальный размер файла, занимаемый на диске, соответствует 1 кластеру.

Загрузочный сектор начинается следующей информацией:

  • EB 58 90 – безусловный переход и сигнатура;
  • 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
  • 00 02 – количество байт в секторе (обычно 512);
  • 1 байт – количество секторов в кластере;
  • 2 байта – количество резервных секторов.

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

  • 0x10 (1 байт) – количество таблиц FAT (обычно 2);
  • 0x20 (4 байта) – количество секторов на диске;
  • 0x2С (4 байта) – номер кластера корневого каталога;
  • 0x47 (11 байт) – метка тома;
  • 0x1FE (2 байта) – сигнатура загрузочного сектора (55 AA ).

Сектор информации файловой системы содержит:

  • 0x00 (4 байта) – сигнатура (52 52 61 41 );
  • 0x1E4 (4 байта) – сигнатура (72 72 41 61 );
  • 0x1E8 (4 байта) – количество свободных кластеров, -1 если не известно;
  • 0x1EС (4 байта) – номер последнего записанного кластера;
  • 0x1FE (2 байта) – сигнатура (55 AA ).

Таблица FAT содержит информацию о состоянии каждого кластера на диске. Младшие 2 байт таблицы FAT хранят F8 FF FF 0F FF FF FF FF (что соответствует состоянию кластеров 0 и 1, физически отсутствующих). Далее состояние каждого кластера содержит номер кластера, в котором продолжается текущий файл или следующую информацию:

  • 00 00 00 00 – кластер свободен;
  • FF FF FF 0F – конец текущего файла.
  • 8 байт – имя файла;
  • 3 байта – расширение файла;

Корневой каталог содержит набор 32-битных записей информации о каждом файле, содержащих следующую информацию:

В случае работы с длинными именами файлов (включая русские имена) кодировка имени файла производится в системе кодировки UTF-16. При этого для кодирования каждого символа отводится 2 байта. При этом имя файла записывается в виде следующей структуры:

  • 1 байт последовательности;
  • 10 байт содержат младшие 5 символов имени файла;
  • 1 байт атрибут;
  • 1 байт резервный;
  • 1 байт – контрольная сумма имени DOS;
  • 12 байт содержат младшие 3 символа имени файла;
  • 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 , если произошла ошибка.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#include
int main() {
FILE *fp;
char name = "my.txt" ;
if ((fp = fopen(name, "r" )) == NULL )
{
printf("Не удалось открыть файл" );
getchar();
return 0;
}
// открыть файл удалось
... // требуемые действия над данными
fclose(fp);
getchar();
return 0;
}

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

char fgetc(поток);


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

Запись символа в файл :

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

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

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

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

Функция fopen() открывает для использования поток, связывает файл с данным потоком и затем возвращает указатель FILE на данный поток. Чаще всего файл рас­сматривается как дисковый файл. Функция fopen() имеет следующий прототип:

FILE *fopen(const char *имя_файла, const char *режим);

Где режим указывает на строку, содержащую желаемый режим открытия файла. Допустимые зна­чения для режим в Borland С++ показаны в таблице. имя_файла должно быть строкой симво­лов, предоставляющей корректное имя файла операционной системе, и может содержать указа­ние пути.

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

Как показывает таблица, файл может быть открыт или в текстовом, или в двоичном режи­ме. В текстовом режиме при вводе последовательность возврат каретки и перевод строки трансли­руется в символ новой строки. При выводе справедливо обратное: символ новой строки трансли­руется в возврат каретки и перевод строки. В двоичных файлах такого перевода не происходит. Когда в аргументе режима не указаны ни t, ни b, то статус файла текстовый/двоичный определя­ется значением глобальной переменной _fmode, определенной в Borland С++. По умолчанию fmode установлена в О_ТЕХТ, то есть устанавливается текстовый режим. Если установить _fmode в О_BINARY, то файлы будут открываться в двоичном режиме. (Эти макросы определены в fcntl.h.) Естественно, использование явно указанных t или b устраняет эффекты, связанные с переменной _fmode. Кроме этого, _fmode характерна только для продуктов Borland. Она не определена в системе ввода/вывода ANSI С.

Если необходимо открыть файл с именем test на запись, то следует написать:

Fp = fopen ("test", "w") ;

Где fp - это переменная типа FILE *. Тем не менее обычно можно увидеть следующее:

If((fp = fopen("test", "w"))==NULL) {
puts ("Cannot open file.");
exit (1);
}

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

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

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

Открытие файла на чтение требует наличия файла. Если файл не существует, то будет возвращена ошибка. Если файл открыт для операции чтения/записи, то он не удаляется при наличии, а если файл не существует, то он создается.

Таблица: Допустимые значения режимов

Значение

Открывает файл для чтения. (Открывает по умолчанию как текстовый файл.)

Создает файл для записи. (Открывает по умолчанию как текстовый файл.)

Присоединяет к файлу. (Открывает по умолчанию как текстовый файл.)

Открывает двоичный файл для чтения.

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

Присоединяет к двоичному файлу.

Открывает файл для чтения/записи. (Открывает по умолчанию как текстовый файл.)

Создает файл для чтения/записи. (Открывает по умолчанию как текстовый файл.)

Присоединяет или создает файл для чтения/записи. (Открывает по умолчанию как текстовый файл.)

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

Создает двоичный файл для чтения/записи.

Присоединяет или создает двоичный файл для чтения/записи.

Создает текстовый файл для записи.

Присоединяет к текстовому файлу.

Открывает текстовый файл для чтения.

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

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

В этом разделе будут рассотрены два способа работы с фыйлами и стандартный класс MFC CFileDialog.


1. Работа с файлами в C (работает и в C++)..


    #include
    #include

Void main(void)
{
FILE *file;
char* file_name = "file.txt";
char load_string = "none";

File = fopen(file_name, "w");

Fputs("string", file);

File = fopen(file_name, "r");
if(file != 0)
{
fgets(load_string, 50 , file);
cout }
else
{
cout }
fclose(file);
} Описание функций работы с файломи находятся в библиотеке stdio.h
Сначала надо создать указатель на переменную типа FILE (FILE* file; ).
Открытие файла производится вызовом функции fopen (file = fopen(file_name, "w"); )
Первый параметр этой функции - имя файла, второй - указывает в каком режиме должен быть открыт файл. "w" - открыть для записи, "r" - открыть для чтения, "a" - дополнение файла(это наиболее используемые режимы, хотя есть и другие). Запись и считывание данных из файла осуществляется следующими функциями: fputc, fputs, fgetc, fgets, fprintf, fscanf (описание этих функций смотрите в stdio.h ).
Закрытие файла осуществляется вызовом функции fclose (fclose(file); ).

Работа с файлами с помощью MFC(классы CFile, CStdioFile, ...) и стандартный класс MFC CFileDialog.


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

CFile .

Класс CF ile

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

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

Open .

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

После создания объекта класса CFile можно открыть файл, вызвав метод Open . Методу надо указать путь к открываемому файлу и режим его использования. Прототип метода Open имеет следующий вид:

Virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError=NULL);

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

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

  • CFile::modeCreate - Создается новый файл. Если указанный файл существует, то его содержимое стирается и длина файла устанавливается равной нулю.
  • CFile::modeNoTruncate - Этот файл предназначен для использования совместно с файлом CFile::modeCreate. Если создается уже существующий файл, то его содержимое не будет удалено.

  • CFile::modeRead - Файл открывается только для чтения.
  • CFile::modeReadWrite - Файл открывается для записи и для чтения.
  • CFile::modeWrite - Файл открывается только для записи.
  • CFile::typeText - Используется классами, порожденными от класса CFile, например CStdioFile, для работы с файлами в текстовом режиме. Текстовый режим обеспечивает преобразование комбинации символа возврата каретки и символа перевода строки.
  • CFile::Binary - Используется классами, порожденными от класса CFile, например CStdioFile, для работы с файлами в двоичном режиме.
  • Необязательный параметр pError, который является указателем на объект класса CFileException , используется только в том случае, если выполнение операции с файлом вызовет ошибку. При этом в объект, указываемый pError, будет записана дополнительная информация.

    Метод Open возвращает не нулевое значение, если файл открыт и нуль в случае ошибки. Ошибка при открытии файла может случиться, например, если методу Open указан для чтения несуществующий файл.

    Идентификатор открытого файла

    В состав класса CFile входит элемент данных m_hFile типа UINT. В нем хранится идентификатор открытого файла. Если объект класса CFile уже создан, но файл еще не открыт, то в переменной m_hFile записана константа hFileNull.

    Обычно идентификатор открытого файла непосредственно не используется. Методы класса CFile позволяют выполнять практически любые операции с файлами и не требуют указывать идентификатор файла. Так как m_hFile является элементом класса, то реализация его методов всегда имеет свободный доступ к нему.

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

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

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

    Для доступа к файлам предназначено несколько методов класса CFile : Read, ReadHuge, Write, WriteHuge, Flush . Методы Read и ReadHuge предназначены для чтения данных из предварительно открытого файла. В 32-разрядных операционных системах оба метода могут одновременно считать из файла больше 65535 байт. Спецификация ReadHuge считается устаревшей и оставлена только для совместимости с 16-разрядными операционными системами.

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

    Для записи в файл предназначены методы Write и WriteHuge. В 32-разрядных операционных системах оба метода могут одновременно записывать в файл больше 65535 байт. Методы записывает в открытый файл nCount байт из буфера lpBuf. В случае возникновения ошибки записи, например переполнения диска, методы вызывает обработку исключения.

    Метод Flush

    Когда используется метод Write или WriteHuge для записи данных на диск, они некоторое время могут находиться во временном буфере. Чтобы убедиться, что необходимые изменения внесены в файл на диске, нужно воспользоваться методом Flush.

    Операции с файлами

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

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

    Для удаления файлов в классе CFile включен статический метод Remove , позволяющий удалить указанный файл. Этот метод не позволяет удалять каталоги. Если удалить файл невозможно, то метод вызывает исключение.

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

    Виртуальная версия метода GetStatus определяет состояние открытого файла, связанного с данным объектом класса CFile. Этот метод вызывается только тогда, когда объект класса CFile создан и файл открыт.

    Статическая версия метода GetStatus позволяет определить характеристики файла, не связанного с объектом класса CFile. Чтобы воспользоваться этим методом, необязательно предварительно открывать файл.

    Блокировка

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

    Установить блокировку можно с помощью метода LockRange . Чтобы снять установленные блокировки, надо воспользоваться методом UnlockRange . Если в одном файле установлены несколько блокировок, то каждая из них должна сниматься отдельным вызовом метода UnlockRange .

    Позиционирование

    Чтобы переместить указатель текущей позиции файла в новое положение, можно воспользоваться одним из следующих методов класса CFile - Seek, SeekToBegin, SeekToEnd. В состав класса CFile также входят методы, позволяющие установить и изменить длину файла, - GetLength, SetLength .

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

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

    Seek . Он позволяет переместить указатель на определенное число байт относительно начала, конца или текущей позиции указателя.

    Чтобы переместить указатель в начало или конец файла, наиболее удобно использовать специальные методы. Метод

    SeekToBegin перемещает указатель в начало файла, а метод SeekToEnd - в его конец.

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

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

    Текущую позицию указателя файла можно определить с помощью метода

    GetPosition . Возвращаемое методом GetPosition 32-разрядное значение определяет смещение указателя от начала файла.

    Характеристики открытого файла

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

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

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

    Класс C

    MemFile

    В библиотеку MFC входит класс

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

    Работая с объектами класса

    CMemFile , можно использовать практически все методы класса CFile , которые были описаны выше. Можно записывать данные в такой файл или считывать их. Кроме этих методов в состав класса CMemFile включены дополнительные методы.

    Для создания объектов класса CMemFile предназначено два различных конструктора. Первый конструктор CMemFile имеет всего один необязательный параметр nGrowBytes:

    CMemFile(UINT nGrowBytes=1024);

    Этот конструктор создает в оперативной памяти пустой файл. После создания файл автоматически открывается (не нужно вызывать метод Ope

    n).

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

    CMemFile вызывают стандартные функции malloc, realloc и free . Если выделенного блока памяти недостаточно, его размер увеличивается. Увеличение блока памяти файла происходит по частям по nGrowBytes байт. После удаления объекта класса CMemFile используемая память автоматически возвращается системе.

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

    CMemFile(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes=0);

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

    Необязательный параметр nGrowBytes используется более комплексно, чем в первом конструкторе класса. Если nGrowBytes содержит нуль, то созданный файл будет содержать данные из буфера lpBuffer. Длина такого файла будет равна nBufferSize.

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

    CMemFile позволяет получить указатель на область памяти, используемую файлом. Через этот указатель можно непосредственно работать с содержимым файла, не ограничивая себя методами класса CFile . Для получения указателя на буфер файла можно воспользоваться методом Detach. Перед этим полезно определить длину файла (и соответственно размер буфера памяти), вызвав метод GetLength . Detach закрывает данный файл и возвращает указатель на используемый им блок памяти. Если опять потребуется открыть файл и связать с ним оперативный блок памяти, нужно вызвать метод Attach .

    Нужно отметить, что для управления буфером файла класс

    CMemFile вызывает стандартные функции malloc, realloc и free . Поэтому, чтобы не нарушать механизм управления памятью, буфер lpBuffer должен быть создан функциями malloc или calloc .

    Класс CStdioFile

    Тем, кто привык пользоваться функциями потокового ввода/вывода из стандартной библиотеки C и C++, следует обратить внимание на класс

    CStdioFile , наследованный от базового класса CFile . Этот класс позволяет выполнять буферизированный ввод/вывод в текстовом и двоичном режиме. Для объектов класса CStdioFile можно вызывать практически все методы класса CFile. CStdioFile входит элемент данных m_pStream, который содержит указатель на открытый файл. Если объект класса CStdioFile создан, но файл еще не открыт, либо закрыт, то m_pStream содержит константу NULL. CStdioFile имеет три различных конструктора. Первый конструктор класса CStdioFile не имеет параметров. Этот конструктор только создает объект класса, но не открывает никаких файлов. Чтобы открыть файл, надо вызвать метод Open базового класса CFile .

    Второй конструктор класса

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

    Третий конструктор можно использовать, если надо создать объект класса

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

    Для чтения и записи в текстовый файл класс CStdioFile включает два новых метода:

    ReadString и WriteString . Первый метод позволяет прочитать из файла строку символов, а второй метод - записать.

    Примеры записи и чтения из файла

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

    Открытие файла и чтение из него

    CString m_Text; …… // создание стандартной панели выбора файла Open CFileDialog DlgOpen(TRUE,(LPCSTR)"txt",NULL, OFN_HIDEREADONLY,(LPCSTR)" Text Files (*.txt) |*.txt||"); // отображение стандартной панели выбора файла Open if(DlgOpen.DoModal()==IDOK) { // создание объекта и открытие файла для чтения CStdioFile File(DlgOpen.GetPathName(),CFile::modeRead|CFile::typeBinary); // чтение из файла строки CString& ref=m_Text; File.ReadString(ref); // передается ссылка на строку m_Text }

    Открытие файла и запись из него

    CString m_Text; …… // создание стандартной панели выбора файла SaveAs CFileDialog DlgSaveAs(FALSE,(LPCSTR)"txt",NULL, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, (LPCSTR)" Text Files (*.txt) |*.txt||"); // отображение стандартной панели выбора файла SaveAs if(DlgSaveAs.DoModal()==IDOK) { // создание объекта и открытие файла для записи CStdioFile File(DlgSaveAs.GetPathName(), CFile::modeCreate|CFile::modeWrite|CFile::typeBinary); // запись в файл строки File.WriteString((LPCTSTR)m_Text); }
      находится рабочий код программы, выполненной для простоты в виде консольного приложения под MFC. Чтобы программа работала не забудте сделать следующее:

      Запустите программу - Build / Rebuild all (будут ошибки), выберите Build / Set active configuration - Win 32 Realise, выберите пункт меню "Project", далее "Settings...", закладку "C/C++", Category - Code Generation и в пункте "Use run-time library" выберите "Multithreaded". После этого сделайте опять Build / Rebuild all и программа будет работать.