Опубликован: 15.11.2010 | Доступ: свободный | Студентов: 643 / 18 | Оценка: 4.00 / 5.00 | Длительность: 17:30:00
Специальности: Программист
Лекция 8:

Буферизированный (потоковый) ввод-вывод. Часть III

8.2. Файловый ввод-вывод

8.2.1. Ввод-вывод средствами языка Си

Для вывода в файл с помощью стандартных функций потокового вывода на языке Си используются следующие функции:

  • fscanf - для "форматированного ввода" значений из входного потока данных;
  • fgets - для чтения из потока строки символов указанной длины Максимальная длина строки указывается в параметрах функции;
  • getc - для чтения одиночного символа из потока ввода;
  • fread - для "неформатированного ввода" данных (как "текстовых", так и "двоичных") из входного потока. На языке Си эта функция является единственной, которая может читать "не преобразованные двоичные" данные с любого "двоичного" потока (прежде всего - для двоичных файлов);
  • fprintf - для "форматированного вывода" данных в указанный выходной поток. При этом "двоичные" данные преобразуются в текстовые данные, в соответствии со строкой формата;
  • fputs - для записи строки, состоящих из текстовых символов, в выходной поток данных. Ограничение на длину символов не накладывается. Эта функция эффективно работает только с текстовыми файлами;
  • putc - для записи одиночного символа в выходной поток;
  • fwrite - для "неформатированного вывода" данных (как "текстовых", так и "двоичных") в выходной поток. На языке Си эта функция - единственная, которая может записывать "не преобразованные двоичные данные" в поток (прежде всего, для двоичных файлов).

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

  • fopen - функция открывает поток данных. В качестве параметров ей передаются, во-первых, имя файла (краткое или полное путевое имя), во-вторых, режим открытия файла. С помощью этих функций можно открыть файл в текстовом и двоичном режиме (модификаторы режима "t" и "b" ) для чтения, записи и добавления в конец файла данных. Более подробно о модификаторах потока смотрите в приложении №1 (пункт 8.4.) к данной лекции;

    Примечание: при открытии потока всегда проверяйте значение его указателя не равное нулю (значению "NULL" ). Это значение указывает, что при открытии файла произошла ошибка. Если же для ввода-вывода Вы будете использовать "нулевой" указатель, это может привести к серьёзным ошибкам в Вашей программе, вызывающих "отказ системы" и "переполнение буфера";

  • fclose - функция закрывает поток данных. В качестве параметров ей передаётся указатель на закрываемый поток;

    Примечание: при закрытии потока всегда проверяйте значение его указателя не равное нулю (значению "NULL" ). Это значение указывает, что при открытии файла произошла ошибка. Если же Вы будете "закрывать" "нулевой" указатель, это может привести к серьёзным ошибкам в Вашей программе;

  • fcloseall - функция закрывает все открытые файловые потоки данных, исключая stdin, stdout, stdprn, stdaux и stderr ;

Кроме того, для организации эффективной работы с файлами полезными для Вас будут следующие функции:

  • feof - функция обнаруживает конец файла в потоке. Она возвращает ненулевое значение в случае, если достигнут конец файла в открытом потоке. В противном случае она возвращает значение "0" ;
  • ferror - функция обнаруживает ошибку ввода-вывода в потоке. Она возвращает ненулевое значение в случае, если возникла ошибка в открытом потоке. В противном случае она возвращает значение "0" ;

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

  • fseek - функция устанавливает указатель файла в потоке. Эта функция работает с файлами, открытыми для одновременного ввода и вывода. Её описание смотри в приложении №1 (пункт 8.4.) к данной лекции;
  • ftell - функция возвращает положение указателя текущей позиции файла. Эта функция работает с файлами, открытыми для одновременного ввода и вывода. Её описание смотри в приложении №1(пункт 8.4.) к данной лекции;
  • rewind - функция устанавливает указатель в начало потока. Описание к данной функции смотри в приложении №1 (пункт 8.4.) к данной лекции;

Более подробную информацию о функциях потокового ввода-вывода смотри книгу [3].

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

Пример файлового ввода-вывода смотри ниже:

Пример 8.3

/* File ex08003.c Запись значения в текстовый файл */
/* Данный пример тестировался в системе программировани
   Borland C/C++ 3.10 */
#include <stdio.h>
#include <string.h>
#include <conio.h>
#ifndef	STR_LENGTH
#define	STR_LENGTH	5 // Длина строки 3 символа
#endif
void main()
{
	char str[STR_LENGTH]; // Текстовый буфер
	FILE *outputStream; // Выходной поток
	char c, *s;	// Временная переменна
	int icsize;	// Временная переменна
	if( (outputStream = fopen( "tempfile.txt", "wt" )) == NULL ) // Открытие потока
	{
		fprintf( stderr, "\nОшибка открытия файла: %s", "tempfile.txt" );
		return;
	}
	memset( str, '\0', STR_LENGTH ); // Обнуляем буфер
	icsize = STR_LENGTH;
	(void) printf( "\nВведите строку из %d символов: ", icsize );
	s = fgets( str, icsize, stdin ); // Читаем не более 2 символов с входного потока
				      // (вместе с нулевым символом)
	if( !s )
	{
		fprintf( stderr, "\nОшибка ввода значения" );
		return;
	}
	(void) fprintf( outputStream, "%2d ", strlen(s) ); //Выводим длину строки
	(void) fprintf( outputStream, "%4s", s ); // Выводим значение строки
	if( !outputStream )
		fclose( outputStream );  // Закрываем поток
// Завершение работы программы
	puts( "\nPress any key to continue...");
	while( !(c = getch()) ); // Цикл пока не нажата клавиша
}
Листинг .

Пример 8.4

/* File ex08004.c Чтение данных из текстового файла */
/* Данный пример тестировался в системе программировани
   Borland C/C++ 3.10 */
#include <stdio.h>
#include <string.h>
#include <conio.h>
#ifndef	STR_LENGTH
#define	STR_LENGTH	5 // Длина строки 3 символа
#endif
void main()
{
	char str[STR_LENGTH]; // Текстовый буфер
	FILE *inputStream; // Входной поток
	char c, *s;	// Временная переменна
	int icsize;	// Временная переменна
	icsize = STR_LENGTH;
	if( (inputStream = fopen( "tempfile.txt", "rt" )) == NULL ) // Открытие потока
	{
		fprintf( stderr, "\nОшибка открытия файла: %s", "tempfile.txt" );
		return;
	}
	memset( str, '\0', STR_LENGTH ); // Обнуляем буфер
	if( !fscanf( inputStream, "%d", icsize ) )
	{
		fprintf( stderr, "\nОшибка чтения или неправильный формат файла: %s", "tempfile.txt" );
		if( !inputStream )
				fclose( inputStream );  // Закрываем поток
		return;
	}
	if( icsize > STR_LENGTH ) // Проверка на длину строки
	{
		fprintf( stderr, "\nНеправильный формат файла: %s", "tempfile.txt" );
		if( !inputStream )
				fclose( inputStream );  // Закрываем поток
		return;
	}
	if( !(s = fgets( str, icsize+2, inputStream )) ) // Чтение строки из файла
	{
		fprintf( stderr, "\nОшибка чтения или неправильный формат файла: %s", "tempfile.txt" );
		if( !inputStream )
				fclose( inputStream );  // Закрываем поток
		return;
	}
	if( !inputStream )
		fclose( inputStream );  // Закрываем поток
	printf( "\nДлина строки: %2d символов,", strlen(s) ); //Выводим длину строки
	printf( "\nЗначение строки: %5s.", s ); // Выводим значение строки
// Завершение работы программы
	puts( "\nPress any key to continue...");
	while( !(c = getch()) ); // Цикл пока не нажата клавиша
	return;
}
Листинг .

8.2.2. Ввод-вывод средствами языка C++

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

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

Для управления потоками используются следующие функции (методы) файлового потока:

  • open - используется для открытия потока и "связанного" с ним файла;
  • close - метод закрывает открытый поток ввода или вывода;
  • tellg - метод читает текущую позицию ввода данных из файла;
  • tellp - метод читает текущую позицию вывода данных в файл;
  • seekg - метод устанавливает позицию ввода данных из файла;
  • seekp - метод устанавливает позицию вывода данных в файл;

Подробнее об этих функциях смотри в приложении №II (8.5) к данной лекции;

Замечание: как можно видеть из списка приведённых функций, в потоках C++, в отличие от функций языка Си, есть различие между позицией ввода и вывода в файл. Учтите это при программировании потокового вывода в файл.

Пример файлового ввода-вывода смотри ниже:

Пример 8.5

/* File ex08005.cpp Запись значения в текстовый файл */
/* Данный пример тестировался в системе программировани
   Borland C/C++ 3.10 */
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <iostream.h>
#include <fstream.h>
#ifndef	STR_LENGTH
#define	STR_LENGTH	5 // Длина строки 3 символа
#endif
void main()
{
	char str[STR_LENGTH]; // Текстовый буфер
	ofstream outputStream( "tempfile.txt" ); // Выходной поток
	char c, *s;	// Временная переменна
	int icsize;	// Временная переменна
	memset( str, '\0', STR_LENGTH ); // Обнуляем буфер
	icsize = STR_LENGTH - 1;
	cerr << "\nВведите строку из " << icsize << " символов\n";
	s = fgets( str, icsize, stdin ); // Читаем не более 4 символов с входного потока
				      // (вместе с нулевым символом)
	if( !s )
	{
		cerr << "\nОшибка ввода значения";
		return;
	}
	if( !outputStream.good()
	 )
	{
		cerr << "\nОшибка вывода данных";
		return;
	}
	outputStream << strlen(s) << " "; //Выводим длину строки
	outputStream << s; // Выводим значение строки
// Завершение работы программы
	puts( "\nPress any key to continue...");
	while( !(c = getch()) ); // Цикл пока не нажата клавиша
	return;
}
Листинг .

Пример 8.6

/* File ex08006.cpp Чтение данных из текстового файла */
/* Данный пример тестировался в системе программировани
   Borland C/C++ 3.10 */
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <iostream.h>
#include <fstream.h>
#ifndef	STR_LENGTH
#define	STR_LENGTH	5 // Длина строки 3 символа
#endif
void main()
{
	char str[STR_LENGTH]; // Текстовый буфер
	ifstream inputStream( "tempfile.txt" ); // Входной поток
	char c, *s;	// Временная переменна
	int icsize;	// Временная переменна
	memset( str, '\0', STR_LENGTH ); // Обнуляем буфер
	if( !inputStream.good() )
	{
		cerr << "\nОшибка чтения или неправильный формат файла: tempfile.txt";
		return;
	}
	inputStream >> icsize;
	if( icsize > STR_LENGTH ) // Проверка на длину строки
	{
		cerr << "\nНеправильный формат файла: tempfile.txt";
		return;
	}
	inputStream >> str; // ???
	if( !inputStream.good() && !inputStream.eof() )
	{
		cerr << "\nОшибка чтения или неправильный формат файла: tempfile.txt";
		return;
	}
	printf( "\nДлина строки: %2d символов,", strlen(str) ); //Выводим длину строки
	printf( "\nЗначение строки: %5s.", str ); // Выводим значение строки
// Завершение работы программы
	puts( "\nPress any key to continue...");
	while( !(c = getch()) ); // Цикл пока не нажата клавиша
}
Листинг .
Дмитрий Карпов
Дмитрий Карпов
Россия, Нижний Новгород
Олег Корсак
Олег Корсак
Латвия, Рига