Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Файловый ввод-вывод (stdio)

.pdf
Скачиваний:
31
Добавлен:
10.08.2019
Размер:
249.38 Кб
Скачать

vk.com/club152685050

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

Стандартный ввод-вывод Потоковый ввод-вывод

Стандартный ввод-вывод

Для использования функций стандартного ввода-вывода необходимо подключить заголовочный файл #include <cstdio>

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

Открытие потока

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

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

Функция fopen() открывает поток и связывает с этим потоком определенный файл. Затем она возвращает указатель этого файла. Чаще всего (а также в оставшейся части этой главы) под файлом подразумевается дисковый файл.

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

Первый параметр - имя открываемого файла в виде С-строки,

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

С:\test\name1.txt - ошибка!!!

С:\\test\\name1.txt - ОК

Второй параметр - режим открытия файла:

 

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

 

"r"

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

 

"w"

открывается пустой файл для записи (если файл существует, он стирается);

"a"

файл открывается для добавления информации в его конец;

"r+"

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

"w+"

открывается пустой файл для чтения и записи (если файл существует, он

стирается);

 

"а+"

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

Режим открытия может также содержать символы t (текстовый режим) или b (двоичный режим), отличающиеся обработкой символов перехода на новую строку. По умолчанию файл открывается в текстовом режиме. В текстовом режиме комбинация символов «возврат каретки» (ASCII 13) и «перевод строки» (ASCII 10)при вводе преобразуются в символ новой строки. При выводе выполняется обратное преобразование: символы новой строки преобразуются в комбинацию кодов возврата каретки (ASCII 13) и конца строки (ASCII 10). В двоичном режиме такие преобразования не выполняются.

"rb"

"wb"

"ab"

"r+b" "rb+" "w+b" "wb+" "а+b" "аb+"

vk.com/club152685050

Пример:

char* filename="d:\\test\\name1.txt"; FILE * f=fopen(filename, "w+");

или в 2 строки:

FILE * f; f=fopen(filename, "w+");

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

путь и тд

//if (f==NULL) printf("Ошибка при открытии файла.\n"); if (!f) printf("Ошибка при открытии файла.\n");

Указатель f используется в дальнейших операциях с потоком. Его передают функциям ввода/вывода в качестве параметра. При открытии потока с ним связывается область памяти, называемая буфером. При выводе вся информация направляется в буфер и накапливается там до заполнения буфера или до закрытия потока. Чтение осуществляется блоками, равными размеру буфера, и данные читаются из буфера. Буферизация позволяет более быстро и эффективно обмениваться информацией с внешними устройствами. Следует иметь в виду, что при аварийном завершении программы выходной буфер может быть не выгружен, и возможна потеря данных. С помощью функций setbuf и setvbuf можно управлять размерами и наличием буферов.

Существует пять предопределенных потоков, которые открываются в начале работы программы: стандартный ввод stdin, стандартный вывод stdout, стандартный вывод сообщений об ошибках stderr, стандартный дополнительный поток stdaux и стандартная печать stdprn. Первые три потока по умолчанию относятся к консоли. Эти указатели можно использовать в любой функции ввода/вывода там, где требуется указатель потока.

Закрытие потока

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

fopen().

int fclose(FILE* f)

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

чтобы избежать потери данных. fclose(f);

Функция возвращает: 0, если операция закрытия файла выполнена успешно EOF – в случае ошибки.

Чтобы точно узнать, в чем причина этой ошибки, можно использовать стандартную функцию ferror() (о которой вскоре пойдет речь). Обычно отказ при выполнении fclose() происходит только тогда, когда диск был преждевременно удален (стерт) с дисковода или на диске не осталось свободного места.

Обработка ошибок

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

используются функции feof и ferror:

int feof (FILE* f) возвращает не равное нулю значение, если достигнут конец

файла, в противном случае 0;

int ferror (FILE* f) возвращает не равное нулю значение, если обнаружена

ошибка ввода/вывода, в противном случае 0. void clearerr(FILE * f);

Функция сбрасывает индикаторы ошибки и конца файла.

vk.com/club152685050

Позиционирование по файлу

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

Функция перемещает указатель позиции в потоке. Устанавливает внутренний указатель

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

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

SEEK_SET Начало файла SEEK_CUR Текущее положение файла SEEK_END Конец файла

long int ftell( FILE * filestream );

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

void rewind(FILE *f)

Функция очищает флаги ошибок в потоке f и устанавливает указатель текущей позиции на начало файла

int fgetpos( FILE * filestream, fpos_t * position )

Получить значение текущего положения указателя в файле.

int fsetpos( FILE * filestream, const fpos_t * pos );

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

Основные функции ввода/вывода потока

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

size_t и fpos_t - целое без знака

Чтение символа

getc и fgetc – чтение символа из потока. Две идентичные функции имеются просто

потому, чтобы сохранять совместимость со старыми версиями С. Функции эквивалентны, но getc обычно реализуется в виде макроса.

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

чтения. Прототип этой функции следующий: int fgetc(FILE * f)

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

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

getchar чтение символа из стандартного потока stdin (ввод с клавиатуры)

vk.com/club152685050

Запись символа

putc() и fputc() – запись символа в поток. Функции эквивалентны, putc обычно

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

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

режиме записи. Прототип этой функции следующий: int fputc(int ch, FILE *f);

Функция записывает символ ch в поток f.

где f — это указатель файла, возвращенный функцией fopen(), a ch — выводимый символ. Указатель файла сообщает putc(), в какой именно файл следует записывать символ. Хотя ch и определяется как int, однако записывается только младший байт.

Если функция fputc() выполнилась успешно, то возвращается записанный символ. В противном же случае возвращается EOF.

putchar запись символа в стандартный поток stdout (вывод на экран)

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

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

#include <cstdio> #include <locale> using namespace std; int main()

{

setlocale(LC_ALL, "rus");

char* filename="d:\\test\\file1.txt"; FILE *f;

f=fopen(filename, "r");

FILE* fout=fopen("d:\\test\\new.txt", "w+");

//if (f==NULL) printf("Ошибка при открытии файла.\n");

if (!f) {printf("Ошибка при открытии файла.\n"); exit(1);} if (!fout) {printf("Ошибка при открытии файла.\n"); exit(1);} //посимвольное чтение

char ch=getc(f);

 

// чтение

первого символа

while (!feof(f))

{// пока не

достигнут конец файла

putchar(ch);

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

if (!isdigit(ch))

putc(ch, fout);//запись символа в файл, если он не цифра ch = getc(f);

}

fclose(f);

fclose(fout); return 0;

}

Ввод / вывод строк

char *fgets(char *s, int n, FILE *f);

Функция читает из потока f не более n-1 символов и помещает их в массив, адресуемый указателем s (в строку s).

Символы читаются до тех пор, пока не будет прочитан символ новой строки или конца файла (EOF), либо пока не будет достигнут заданный предел. Символ новой строки при чтении не отбрасывается, а помещается в конец строки. В конец прочитанной строки автоматически записывается нулевой символ (\0)

Функция возвращает NULL при обнаружении ошибки или конца файла, в противном случае — указатель на строку s.

gets – чтение строки из стандартного потока stdin. Символ новой строки при чтении отбрасывается

vk.com/club152685050

int fputs(const char *s, FILE *f);

Функция записывает строку символов s в поток f. Символ конца строки в файл не записывается.

При ошибке возвращает значение EOF, иначе — неотрицательное число.

puts – запись строки в стандартный поток stdout

Пример. Чтение/запись из файла построчно printf("чтение/запись по строкам\n"); rewind(f);

char str[80]; while (!feof(f)){

// if(fgets(str, 10, f)) fgets(str, 80, f); printf("%s", str); fputs(str, fout);

}

Чтение и запись потока байтов fread, fwrite

Записывает данные из заданного буфера в потока

size_t fwrite(const void * buf, size_t size, size_t n, FILE * f );

Функция записывает n элементов длиной size байт из буфера, заданного указателем buf, в поток f. Возвращает число записанных элементов.

size_t fread(void * buf, size_t size, size_t count, FILE *f)

Функция считывает count элементов size байтов в область, заданную указателем buf, из потока f.

Функция возвращает количество прочитанных элементов, которое может быть меньше count, если при чтении произошла ошибка или встретился конец файла.

Пример. Запись/чтение в двоичном режиме чисел и массива.

FILE * fb=fopen("d:\\test\\file.dat", "wb+"); double d = 12.23;

int i = 101;

int mas[5]={1,2,3,-5,10};

fwrite(&mas, sizeof(mas), 1, fb); fwrite(&d, sizeof(double), 1, fb); fwrite(&i, sizeof(int), 1, fb);

rewind(fb);

int m[5]; int i1; double d1; printf("\nВывод данных: \n"); fread(&m, sizeof(m), 1, fb); fread(&d1, sizeof(double), 1, fb); fread(&i1, sizeof(int), 1, fb);

printf("%f\n%d\n", d1, i1); for (int i=0; i<=4; i++)

printf("%d ", m[i]);

//произвольный доступ к файлу printf("\nПятый элемент массива: \n"); fseek(fb, sizeof(int)*4, SEEK_SET); fread(&i1, sizeof(int), 1, fb);

printf("%d\n", i1); fclose(fb);

vk.com/club152685050

Форматированный ввод/вывод

int fprintf(FILE *f, const char * управляющая_строка, ...); int fscanf(FILE *f, const char * управляющая_строка, ...);

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

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

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

Форматируемые теги должны следовать следующему формату записи:

%[флаги][ширина поля][.точность][длинна]спецификатор

Ниже приведены спецификаторы форматирования потоков ввода/вывода:

Спецификато

Описание

Пример

р

 

 

 

 

 

c

Символ

d

 

 

 

d или i

Знаковое десятичное число.

111

 

 

 

e

Экспоненциальная форма записи чисел (мантисса/экспонента) с

3.9265e+2

 

использованием символаe.

 

 

 

 

E

Экспоненциальная форма записи чисел (мантисса/экспонента) с

3.9265E+2

 

использованием символаE.

 

 

 

 

f

Десятичное значение с плавающей точкой.

392.65

 

 

 

g

Используется для обозначения короткого %e или %f

392.65

 

 

 

G

Используется для обозначения короткого %E или %f

392.65

 

 

 

o

Восьмеричная система счисления

610

 

 

 

s

Строка символов.

sample

 

 

 

u

Использовать беззнаковое целое десятичное значение.

7235

 

 

 

x

Использовать беззнаковые шестнадцатеричные значения

7fa

 

 

 

X

Шестнадцатеричные целые без знака (прописные буквы)

7FA

 

 

 

p

Указатель на адрес

B800:0000

 

 

 

n

Ничего не печатается. Аргумент должен быть указателем на

 

 

знаковое целое, где хранится количество символов, написанных

 

 

до сих пор.

 

 

 

 

vk.com/club152685050

%

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

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

Флаг Описание

-Выравнивание по левому краю выделенного поля. По умолчанию стоит правостороннее выравнивание в выделенном поле.

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

(space Если в строке есть символ пробела, он не игнорируется, а попадает в поток вывода.

)

#Используется вместе со спецификаторами o, x или X специфицирующих значение

отличное

от

нуля,

 

или

 

.

0x

0X

Используется вместе

со спецификаторами e, E и f,

принудительно

 

выводит

 

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

если нет цифр в дробной части, десятичная точка не

отображается.

Используется

с

a

,

A

,

e

,

E

,

f

,

F

,

g

или

G

результат

такой

же,

как

и

со

спецификаторами

е

 

или

 

 

Е

, но нули не удаляются.

 

 

 

 

 

0Левая часть после числа заполняется нулями (0) вместо пробелов, если ширина поля больше числа.

ширин Описание

а

number Минимальное количество символов для печати. Если значение для печати короче, чем это число, пустые места заполняются пробелами. Значение не обрезается, даже если оно больше number.

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

.точност

Описание

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ь

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

.number

Для

спецификаторов

 

 

 

целых

чисел

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

: указывает

минимальное

d,

 

i,

 

o,

 

u,

 

x,

 

X

 

 

количество цифр. Если значение,

 

 

 

 

короче, чем это число, пустое место

 

 

заполняется нулями. Значение не обрезается, даже если

number

короче. Точность

 

 

0

означает,

 

что

 

 

 

 

нет

символа

 

 

 

 

 

записанного

 

для

 

значения

0.

 

 

Для

спецификаторов

е

,

Е

и

F

:

это количество цифр, которое будет

напечатано

 

 

после

 

 

 

 

 

 

 

 

 

 

 

де-десятичной

 

 

 

 

точки.

 

 

Для

спецификаторов

 

и

 

: это максимальное

количество

значащих

цифр

для

 

 

g

G

 

 

печати. Для

S

- это

максимальное количество символов для печати. По умолчанию

 

 

все

 

символы

выводятся

пока

 

не

встретится

нулевой

символ.

 

 

Для

c

:

этот

 

 

 

 

 

 

 

параметр

 

 

 

 

 

 

 

не

имеет

 

значения.

 

 

При

 

отсутствии этого параметра, точность по умолчанию равна 1. Если срок

 

 

указан без явного значения для точности, значение 0.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

.*

 

Точность не указана в строке формата, но в качестве дополнительного аргумента

 

 

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

 

 

отформатирован.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

длинн

Описание

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

vk.com/club152685050

а

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

h

Короткий

 

или беззнаковый короткий

 

(применяется только к целым

int

int

 

спецификаторам:

i

,

d

,

o

,

u

,

x

и

X

).

lДлинный int или длинный беззнаковый int, применяется к целым спецификаторам (i, d, o, u, x и X), а также к широким символам или строкам с широкими символами, для спецификаторов c и s.

Дополнительные аргументы

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

Возвращаемое значение

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

Вслучае неудачи, возвращается отрицательное число.

scanf -форматированный ввод из стандартного потока stdin printf форматированный вывод в стандартный поток stdout

Пример. Запись/чтение данных из файла с помощью функций форматированного

ввода/вывода.

char * fname="d:\\test\\file3.txt"; FILE * f=fopen(fname, "w");

char s[80]; int a;

printf("Введите строку и число: "); scanf("%s%d", s, &a); // читать с клавиатуры

//fscanf(stdin, "%s%d", s, &a); // читать с клавиатуры fprintf(f, "%s %d", s, a); //запись в файл

fclose(f);

f=fopen(fname,"r"); int a1; char s1[80];

fscanf(f, "%s%d", s1, &a1); // чтение из файла printf("Строка: %s\nЧисло: %d\n", s1, a1); // вывод на экран //fprintf(stdout, "%s %d", s1, a1); // вывод на экран

Хотя читать разносортные данные из файлов на дисках и писать их в файлы, расположенные также на дисках, часто легче всего именно с помошью функций fprintf() и fscanf(), но это не всегда самый эффективный способ выполнения операций чтения и записи. Так как данные в формате ASCII записываются так, как они должны появиться на экране (а не в двоичном виде), то каждый вызов этих функций сопряжен с определенными накладными расходами. Поэтому, если надо заботиться о размере файла или скорости, то, скорее всего, придется использовать fread() и fwrite()

intremove( constchar* fname );

Функция remove удаляет файл, имя которого указано в параметре fname.

intrename(constchar* oldfilename,constchar* newfilename );

FILE * tmpfile ( void );

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