Программная инженерия. 1 курс 1 семестр / Лекции / L-06.OrganizaciyaVVvSi
.pdfДвоичные и текстовые режимы доступа к файлам
Закрытие файла производится с помощью функции fclose: int fclose(FILE *stream);
«Перемотка» файла в начало : void rewind(FILE *stream);
В потоке *stream эта функция смещает указатель чтения записи в начало файла.
Позиционирование указателя чтения-записи
int fseek(FILE *stream, long int offset, int whence);
Смещение задаётся переменной или выражением типа long. Может быть меньше нуля, т.е.
Можно "ходить" по файлу в разные стороны:
offset- смещение,
whence — начало отсчёта.
Начало отсчёта задаётся одной из определённых констант:
SEEK_SET(имеет значение 0) – начало файла
SEEK_CUR(имеет значение 1) – текущая позиция
SEEK_END(имеет значение 2) – конец файла
fseek(fp, 0L, SEEK_SET); /* перемещение к началу файла из произвольной позиции */
Так мы можем перейти к началу файла из произвольной позиции.
Посимвольный ввод:
int fgetc(FILE *stream);
Функция считывает один символ с текущей позиции потока и перемещает указатель файла на следующий символ.
Ошибка, если конец файла - EOF.
Посимвольный вывод:
int fputc(int c, FILE *stream);
Ввод строки из файла:
char *fgets(char *s, int n, FILE *stream);
Читает из файла не более n-1 символов и размещает их по адресу s.
Символов может быть меньше, чем n-1, если встретился \n или EOF.
Запись строки в файл:
int fputs(const char *s, FILE *stream);
Записывает строку, ограниченную \0, в файл и возвращает неотрицательное целое число.
При неудаче возвращает EOF. Не заменяет ноль-терминатор на перевод новой строки.
Запись данных в поток и чтение из потока:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
В файлах можно хранить потоки данных, состоящих из
фиксированного числа последовательных байт.
Именно вышеуказанные функции fread и fwrite осуществляют последовательные запись\чтение блоков.
Функция fread считывает элементы данных nmemb (с размером каждого size байтов) с потока, на который указывает stream, и сохраняет их в позиции, на которую указывает ptr.
Функция fwrite записывает элементы данных nmemb (с размером каждого size байтов) в поток, на который указывает stream, при получении элементов с той позиции, на которую
указывает ptr.
31
Двоичные и текстовые режимы доступа к файлам
Библиотека stdio.h поддерживает текстовые и бинарные (двоичные) потоки.
Текстовый поток – это последовательность строк, каждая из которых заканчивается символом ‘\n’.
ОС может потребовать коррекции текстового потока.
Например, при вводе текстового потока система преобразует
символы возврат каретки 0x13 и перевод строки 0x10 в
одиночный символ ‘\n’.
При обнаружении в текстовом файле символа с кодом 26 (0x26), т.е. признака конца файла, чтение файла в текстовом режиме
заканчивается, хотя файл может иметь продолжение.
При выводе текстового потока в среду операционной системы происходит обратное преобразование.
При осуществлении операции ввода-вывода в текстовом режиме:
При записи информации в файл символ новой строки преобразуется в пару символов CR и LF.
При чтении из файла эта пара символов преобразуется обратно в символ \n.
В конце файла записывается EOF (0x1A) – End Of File – конец файла.
При считывании информации прочитать находящуюся после EOF не удаётся.
Бинарный поток – это последовательность не преобразуемых байтов, представляющих собой некоторые промежуточные данные, которые обладают тем свойством, что если их записать, а затем прочесть той же системой ввода-вывода, то будет получена информация, совпадающая с исходной.
При выполнении ввода-вывода в двоичном режиме никакого преобразования символов не происходит и все остальные рассматриваются как не имеющие особого значения символы.
Открытие и закрытие потоков
Функции работы с файлами определены в заголовочном файле stdio.h
Указатель на поток: FILE *fp;
Открытие файла: fp=fopen(имя_файла, режим_открытия);
Пример:
FILE *fp; fp=fopen("t.txt", "r");
При открытии файла он связывается со структурой,
определённой в типе FILE.
В ней содержатся компоненты, с помощью которых ведётся работа с потоком.
Указатель на буфер, указатель текущей позиции в потоке,
флаги состояния файла, размер внутреннего буфера и т.п.
При открытии потока в программу возвращается указатель на поток, являющийся указателем на объект структурного типа
FILE.
Режимы открытия:
"w" - Новый текстовый файл открывается для записи. Если файл
уже существовал, то старый стирается и создаётся новый.
"r" — Существующий текстовый файл открывается для чтения.
"a" — Текстовый файл открывается для добавления новой информации в конец файла.
"w+" - Новый текстовый файл открывается для записи и последующих многократных исправлений. Стирает файл, если он уже есть и создаёт новый.
"r+" - Существующий файл открывается как для чтения, так и для записи в любое место файла
"a+" - Текстовый файл открывается или создаётся и становится доступным для изменений.
Для использования этих же режимов, но для двоичных файлов, к
ним добавляется буква b. |
32 |
|
Программа чтения данных из файла |
|
# include <stdio.h> |
|
// Чтение данных файла (продолжение 1-й части) |
int main (void) |
|
col=fscanf (f_cht, %x %d %o %lf %f %c %s %c %s”, &k, &k1, |
{ |
|
&k2, &l, &x, &ch, str, &str[3], &str[4]); |
int k, // Данные будут прочитаны из файла и |
if (col!=9) |
|
k1, /* могут использоваться в данной |
{ |
|
программе */ |
|
printf (”\nДанные прочитаны с ошибками.”); |
k2; |
|
return 2; |
float x; |
|
} |
long l; |
|
// Закрываем файл. |
char ch, |
|
col=fclose (f_cht); |
str[15]; |
|
if (col==EOF) /* EOF – это значение функции fclose при |
file *f_cht; |
// Указатель на файл для чтения. |
ошибке */ |
int col; |
// Возвращаемое значение fscanf. |
// При успехе возвращается 0 |
// Открываем файл «f1.dat» для чтения. |
{ |
|
f_cht=fopen (“f1.dat”, “r”); |
print f(“\nФайл f1.dat не закрыт.”); |
|
if (f_cht==NULL) /* NULL–нулевой указатель |
return 3; |
|
(означает ошибку) */ |
|
} |
{ |
|
return 0; |
printf (“\nФайл f1.dat для чтения не открыт. |
} //конец программы чтения из файла |
|
Ошибка!”); |
|
return 1;
}
33
Примеры файлового ввода-вывода
# include <stdio.h> |
// Для функции ввода/вывода. |
|
int main (void) |
// Возвращает 0 при успехе. |
|
{ |
// Данные для записи в файл |
|
int n=7; |
||
|
||
long int ln=12l; |
|
|
short int sn=5; |
|
|
float x=1.5e2; |
|
long double ld=2.0e-3L;
file *f_zap; |
// Указатель на файл для записи |
int col; |
// Возвращаемое значение для fclose. |
|
// Открываем файл f2.out для записи. |
f_zap=fopen (“f2.out”, “w”); |
|
if (f_zap==NULL) |
|
{ |
|
printf (“\nФайл f2.out для записи не открыт.”); |
|
return 1; |
|
} |
|
… |
|
} |
// end main () |
Просмотрев содержимое файла любым текстовым редактором, можно убедиться, что данные в нем располагаются точно так, как на экране, если воспользоваться функцией printf с такими же списками параметров.
FILE *f; //объявляется указатель на файл f;
f = fopen ("Dat_sp.dat ", "w"); /* Открывается для записи файл с логическим именем f, имеющий физическое имя Dat_sp.dat или более кратко: */
FILE *f = fopen ("Dat_sp.dat", "w");
По умолчанию файл открывается в текстовом режиме.
Текстовый режим отличается от двоичного тем, что при открытии файла как текстового, пара символов «перевод строки» и «возврат каретки» заменяется на один символ «перевод строки» для всех функций записи данных в файл.
И для всех функций вывода – наоборот – символ «перевод строки» заменяется на два символа – «перевод строки» и «возврат каретки».
#include<stdio.h> void main(void)
{
FILE *f1;
int a=2, b=3;
if( ! (f1 = fopen(“f_rez.txt”,”w+t”) ) ) // f1 = NULL
{
puts(“Open File Error!”); |
|
return; |
// exit(1); |
}
fprintf(f1,”\t Файл результатов \n”); fprintf(f1,” %d плюс %d = %d\n”, a, b, a+b); fclose(f1);
}
34
Пример использования ввода-вывода на Си |
|
|
|||
Код программы |
Программа |
|
|
||
|
s1 |
|
s2 |
|
|
|
|
|
|
Ядро ОС |
|
|
fd1 |
|
FILE |
->file1 |
|
|
|
|
|||
|
FILE |
fd2 |
|
->file2 |
|
|
|
|
|
||
|
Станд. библиотека |
|
|
||
|
|
GLibC |
|
|
|
|
|
|
file1 |
file2 |
|
|
|
|
Файловая система |
Функция fscanf считывает данные с текущей позиции вводимого потока в заданный список аргументом в соответствии с заданным условием.
Общая структура выглядит так: fscanf (stream, format-string [, argument ...]);
где stream – поток данных, который мы считываем, format-string – условия при которых данные сохранятся и [, argument1, |
|
argument2, …] –аргументы. |
35 |
Пример использования ввода-вывода на С/С++
Код программы
file1
Файловая система
Пример кода:
char str [60]; FILE * aF;
aF = fopen ("file.txt","w+"); fscanf (aF, "%s", str); fclose (aF);
Впервых двух строках идет объявление необходимых в работе переменных – массива символов str и файла (а если корректней, то потока) aF.
Далее идет инициализация aF, путем открытия файла file.txt. На следующей строке идет нужная нам функция. Первой переменной в fscanf является aF – тот поток, из которого мы будем считывать данные.
Далее идет идентификатор %s, показывающий, что считывание будет происходить до 1-ого пробела.
Возможны и другие идентификаторы, например %i, сохраняющее любое целое число 10-тичной, 8-ричной или 16-ричной системы. И последнее str – куда записывается данные из потока.
Витоге в str сохранятся символы из потока, начиная с первого символа, пока не встретится пробел.
Последняя строка закрывает файл.
36
Приложение. Функции ВВ getchar( ) и putchar(х)
Операции ввода/вывода в языке Си организованы посредством библиотечных функций (причем их довольно много).
Самый простой механизм ввода - чтение по одному символу из стандартного входного потока (с клавиатуры) с помощью функции getchar( ).
Она имеет следующий прототип (т.е. описание заголовка):
int getchar(void);
Здесь определен тип единственного аргумента (void) и тип возвращаемого функцией значения (int).
Оператор вида:
х = getchar( );
присваивает переменной х очередной вводимый символ. Переменная х должна иметь символьный или целый тип.
Другая функция - putchar(х) выдает значение переменной x в стандартный выходной поток (на экран дисплея).
Функция putchar( ) имеет прототип:
int putchar(int);
Объявления getchar( ) и putchar( ) сделаны в заголовочном файле stdio.h, содержащем описания заголовков библиотечных функций стандартного ввода/вывода.
Чтобы библиотечные функции стали доступны программе, к ней необходимо подключить данный файл.
Подключение осуществляется с помощью директивы препроцессора
#include <stdio.h>
помещаемой в начало программы
Заметим, что для функции getchar( ) после выбора символа необходимо нажать клавишу <Enter>.
Иногда это создает определенные неудобства.
Функции getch( ) и getche( ) устраняют их. Они имеют следующие прототипы:
int getch(void);
int getche(void);
Обе эти функции вводят символ сразу же после нажатия соответствующей клавиши (здесь не надо дополнительно нажимать клавишу <Enter>).
Отличие между ними заключается в том, что getche( ) отображает вводимый символ на экране дисплея, а getch( ) - нет.
Прототипы этих функций содержатся в файле conio.h (консольный ввод/вывод).
Для их использования файл conio.h также следует подключить к программе с помощью директивы #include <conio.h>
37
Приложение. Форматированный вывод данных. Функция printf( )
Функция printf( ) (прототип содержится в файле stdio.h: #include <stdio.h>) обеспечивает форматированный вывод.
Ее можно записать в следующем формальном виде:
рrintf ("управляющая строка", аргумент _1, аргумент
_2,...);
Управляющая строка содержит компоненты трех типов:
1)обычные символы, которые просто копируются в стандартный выходной поток (выводятся на экран дисплея);
2)спецификации преобразования, каждая из которых вызывает вывод на экран очередного аргумента из последующего списка;
3)управляющие символьные константы.
Каждая спецификация преобразования начинается со знака % и заканчивается некоторым символом, задающим преобразование.
Между знаком % и символом преобразования могут встречаться другие знаки в соответствии со следующим форматом:
% [признаки] [ширина_поля] [точность] [F|N|h|l|L] c_n
Все параметры в квадратных скобках не являются обязательными.
На месте параметра c_n (символ преобразования) могут быть записаны:
с - значением аргумента является символ;
d или i - значением аргумента является десятичное целое число;
е - значением аргумента является вещественное десятичное число в экспоненциальной форме вида 1.23e+2;
Е - значением аргумента является вещественное десятичное число в экспоненциальной форме вида 1.23E+2;
f - значением аргумента является вещественное десятичное число с плавающей точкой;
g (или G) - используется, как е или f, и исключает вывод незначащих нулей;
о - значением аргумента является восьмеричное целое число; s - значением аргумента является строка символов (символы
строки выводятся до тех пор, пока не встретится символ конца строки или же не будет, выведено число символов, заданное точностью);
u - значением аргумента является беззнаковое целое число; х - значением аргумента является шестнадцатеричное целое
число с цифрами 0,..., 9, а, b, с, d, е, f;
X - значением аргумента является шестнадцатеричное целое число с цифрами 0,..., 9, А, В, С, О, Е, F;
р - значением аргумента является указатель;
n - применяется в операциях форматирования. Аргумент, соответствующий этому символу спецификации, должен быть указателем на целое. В него возвращается номер позиции строки (отображаемой на экране), в которой записана спецификация %n.
38
Приложение. Форматированный вывод данных. Функция printf( )
Необязательные параметры в спецификации преобразования:
признак минус (-) указывает, что преобразованный параметр должен быть выровнен влево в своем поле;
признак плюс (+) требует вывода результата со знаком; строка цифр, задающая минимальный размер поля (ширина
поля). Здесь может так же использоваться символ *, который тоже позволяет задать минимальную ширину поля и точность представления выводимого числа;
точка (.), отделяющая размер поля от последующей строки цифр;
строка цифр, задающая максимальное число выводимых символов, или же количество цифр, выводимых справа от десятичной точки в значениях типов float или double (точность);
символ F, определяющий указатель типа far; символ N, определяющий указатель типа near; символ h, определяющий аргумент типа short int
(используется вместе с символами преобразования d, i, о, u, х, Х); символ l, указывающий, что соответствующий аргумент имеет
тип long (в случае символов преобразования d, i, о, u, х, X) или double (в случае символов преобразования е, Е, f, g, G);
символ L, указывающий, что соответствующий аргумент имеет тип long double (используется вместе с символами преобразований е, Е, f, g, G);
символ #, который может встречаться перед символами преобразования g, f, е и перед символом х. В первом случае всегда будет выводиться десятичная точка, а во втором - префикс 0x перед соответствующим шестнадцатеричным числом.
Если после знака % записан не символ преобразования, то он выводится на экран. Таким образом, строка %% приводит к
Функция printf( ) использует управляющую строку, чтобы определить, сколько всего аргументов и каковы их типы. Аргументами могут быть переменные, константы, выражения, вызовы функций; главное, чтобы их значения соответствовали заданной спецификации.
При наличии ошибок, например, в числе аргументов или типе преобразования, результаты будут неверными.
Среди управляющих символьных констант наиболее часто используются следующие:
\а - для кратковременной подачи звукового сигнала; \b - для перевода курсора влево на одну позицию; \f - для подачи формата;
\n - для перехода на новую строку; \r - для возврата каретки;
\t - горизонтальная табуляция; \v - вертикальная табуляция; \\ - вывод символа \; \' - вывод символа ' ; \" - вывод символа "; \? - вывод символа ?.
Например, в результате вызова функции: printf("\tComputer\n%d\n", i);
Сначала выполняется горизонтальная табуляция (\t), т.е. курсор сместится от края экрана, затем на экран будет выведено слово Computer, после этого курсор переместится в начало следующей строки (\n), затем будет выведено целое число i по формату %d (десятичное целое), и, окончательно, курсор перейдет в начало новой строки (\n).
Напечатать строку символов можно и так: printf("Это строка символов");
выводу на экран знака %. |
39 |
Приложение. Форматированный ввод данных. Функция scanf( )
Функция scanf( ) (прототип содержится в файле stdio.h) обеспечивает форматированный ввод.
Ее можно записать в следующем формальном виде:
scanf("управляющая строка", аргумент_1, аргумент_2,...);
Аргументы scanf( ) должны быть указателями на соответствующие значения.
Для этого перед именем переменной записывается символ &. Назначение указателей будет рассмотрено далее.
Управляющая строка содержит спецификации преобразования и используется для установления количества и типов аргументов. В нее могут включаться:
пробелы, символы табуляции и перехода на новую строку (все они игнорируются);
спецификации преобразования, состоящие из знака %, возможно, символа * (запрещение присваивания), возможно, числа, задающего максимальный размер поля, и самого символа преобразования;
обычные символы, кроме % (считается, что они должны совпадать с очередными неизвестными символами во входном потоке).
Рассмотрим символы преобразования функции scanf( )
(указываются после символа %):
с - на входе ожидается появление одиночного символа;
d или i - на входе ожидается десятичное целое число и аргумент является указателем на переменную типа int;
D или l - на входе ожидается десятичное целое число и аргумент является указателем на переменную типа long;
е или Е - на входе ожидается вещественное число с плавающей точкой;
f - на входе ожидается вещественное число с плавающей точкой; g или G - на входе ожидается вещественное число с плавающей
точкой; о - на входе ожидается восьмеричное целое число и аргумент
является указателем на переменную типа int;
О - на входе ожидается восьмеричное целое число и аргумент является указателем на переменную типа long;
s - на входе ожидается появление строки символов;
х - на входе ожидается шестнадцатеричное целое число и аргумент является указателем на переменную типа int;
Х - на входе ожидается шестнадцатеричное целое число и аргумент является указателем на переменную типа long;
р - на входе ожидается появление указателя в виде
шестнадцатеричного числа;
n - применяется в операциях форматирования. Аргумент, соответствующий этому символу спецификации, должен быть указателем на целое. В него возвращается номер позиции (после ввода), в которой записана спецификация %n;
u - на входе ожидается беззнаковое целое число и аргумент является указателем на переменную типа unsigned int;
U - на входе ожидается беззнаковое целое число и аргумент является указателем на переменную типа unsigned long;
[ ] - сканирует входную строку для получения символов.
Перед некоторыми символами преобразования могут записываться следующие модификаторы:
F - изменяет указатель, заданный по умолчанию, на указатель типа far;
N - изменяет указатель, заданный по умолчанию, на указатель типа near;
h - преобразует аргумент к типу short int (может записываться перед символами d, i, о, u, х);
l - преобразует аргумент к типу long int (может записываться перед
символами d, i, o, u, x); |
|
L - преобразует аргумент к типу long double (может записываться |
40 |
перед символами е, f, g). |