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

advertisement
Файловый ввод/вывод с применением потоков

Библиотека С++ содержит три специализированных класса для
файлового ввода.вывода:
 ifstersm: Для операций с входным дисковым файлом
 ofsteram: Для операций с выходным дисковым файлом
 fstream: Для входных и выходных файлов

Эти классы являются производными соответственно от istream,
osteram и iosteram

Т.о. они наследуют все их функциональные особенности
(перегруженные операции <<, >> для встроенных типов, флаги
формата, состояния потока и т.д.)
Файловый ввод/вывод с применением потоков





конструкторы файловых потоков
открытие файла
режимы доступа
замена буфера потока
закрытие буфера
1. Конструкторы файловых потоков


Для каждого из трех классов файловых потоков прeдусмотрено
четыре конструктора
1) Конструировать объект не открывая файла
ifstersm(); ofsteram(); fstream();

2) Конструировать объект, открыть файл и прикрепить объект к
файлу ifsteram( const char *name,
int omode = ios::in,
int prot = filebuf::openprot );
ofsteram( const char *name,
int omode = ios::out,
int prot = filebuf::openprot );
fsteram( const char *name,
int omode,
int prot = filebuf::openprot );

3) Конструировать объект и прикрепить объект
существующему файлу. Указывается дескриптор файла
к
уже
ifstersm(int f);
ofsteram(int f);
fstream(int f);

4) Конструировать объект, ассоциированный с указанным буфером,
прикрепить объект к уже открытому файлу. Специфируется
дескриптор файла
ifstersm(int f, char *b, int len);
ofsteram(int f, char *b, int len);
fstream(int f, char *b, int len);
2. Открытие файла

Чтобы открыть файл можно использовать конструкторы ifstersm,
ofsteram, fstream

Пример применения ifstersm, ofsteram
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{ cout << "Введите имя входного файла: ";
char fname[_MAX_PATH]; cin >> fname;
ifstream ifs(fname); // Открыть поток
if (!ifs) { cout << "Невозможно открыть файл"; return 0; } // Проверить поток
cout << "Введите имя выходного файла:"; cin >> fname;
ofstream ofs(fname);
if (!ofs) { cout << "Невозможно открыть файл"; return 0; }
char c;
while (ifs && ofs) // Пока не произойдет ошибки
{ ifs.get(c);
// Прочитать символ
c =toupper(c); // Перевести в верхний режим
ofs.put(c);
// Записать в выходной поток
cout << '.';
// Показать, что процесс жив
}
cout << endl << "Выходной файл является копией входного"
<< "в верхнем регистре" << endl;
return 0;
}
Пример: открыть файл, применив метод open потока fstream
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
int main(void)
{ fstream fin; char fname[_MAX_PATH];
cout << "Введите имя файла: "; cin >> fname;
fin.open( fname, ios::in); // Открыть входной файл
if (fin)
// Проверить поток
{ cout << "Файл открыт успешно" << endl;
fin.close();
// Закрыть файл
}
else { cout << "Ошибка" << endl; }
return 0;
}
3. Режимы доступа

При открытии файла можно специфицировать параметр режим
доступа, чтобы указать каким образом файл должен открываться

Параметр можно составить из перечислителей битовых масок,
определяемых классом ios.
enum open_mode {
in = 0x01,
// Открыть для чтения
out = 0x02,
// Открыть для записи (подразумевает ios::trunc,
// если не специфицированы ios::in, ios::ate, ios::app
ate = 0x04,
// искать eof при открытии
app = 0x08,
// Присоединить; добавить в конец файла
// подразумевается ios::out)
trunc = 0x10,
// изменять файл, если уже существует
nocreate =0x20, // показать ошибку, если файл не существует
noreplace =0x40, // показать ошибку, если файл уже существует
binary =0x80
// двоичный (не текстовый ) файл
};

Параметр mode в конструкторах и методах классов ifstream и ofstream
имеют значения по умолчанию. Это ios:in и ios::out по умолчанию.

Пример использования параметра mode:
#include <iostream.h>
#include <fstream.h>
const int MAX_LEN=80;
const char fname[]= "NEWFILE";
int main(void)
// Создать новый файл, если только он уже не существует
{ ofstream ofs (fname, ios:out | ios::noreplace);
if (!ofs) { cout << "Ошибка" << fname << "уже существует" << endl; }
else
{ ofs << "Привет, я новый файл";
ofs.close();
// Закрыть файл
fstream fs;
// Определить новый объект
fs.open(fname, ios::out | ios::ate); // Открыть файл и установить его на EOF
fs << "к которому сделано добавление";
fs.close;
fstream ifs(fname);
//Снова открыть как входной
if (ifs)
{ cout << "Старый файл:" << endl;
char line[MAX_LEN];
ifs.getline(line, sizeof(line));
cout << line;
}
else { cout << "Ошибка при повторном открытии" << fname << endl; }
}
return 0;
}
4. Замена буфера потока

Можно управлять буферизацией потока с помощью метода setbuf.
Эта функция ассоциирует с потоком указанный буфер
void setbuf(char *p, int len);
p - адрес буфера
len - длина буфера
5. Закрытие буфера

В классах файловых потоков имеется метод close, который:
 опорожняет поток
 закрывает, закрепленный за потоком файл

Если при попытке закрыть файл, происходит ошибка,
устанавливается флаг failbit состояния потока. Предполагается, что
деструктор файлового объекта (или его базового класса)
автоматически закрывает класс.
Неформатированный ввод/вывод
чтение/запись необработанных данных
 чтение символа
 чтение строки
Эти функции позволяют читать/записывать байты данных без
модификации и часто применяются при работе с бинарными
файлами.



В бинарном режиме данные при вводе/выводе не интерпретируются.
Байты читаются и записываются без какой-либо модификации.
Чтобы открыть файл в бинарном режиме, включите флаг ios::binary в
параметр open_mode, передаваемый конструктору потока или
функции open.

В следующем примере файл открывается в двоичном и текстовом
форматах:
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
int main(void)
{ fstream fin; char name[_MAX_PATH];
cout << "Введите имя входного файла: "; cin >> name;
ifsream ifbin( name, ios::in | ios::binary);
ifsream iftxt( name, ios::in);
if (!iftxt || !ifbin)
// Проверить поток
{ cout << "Ошибка при открытии файла " << name << endl;
return 0; }
int countInBin = 0;
do { if (ifbin.get() != EOF) counInBin++; } while (ifbin);
cout << "Число символов, прочитанных в режиме binary ="
<< countInBin << endl;
int countInTxt = 0;
do { if (iftxt.get() != EOF) counInTxt++; } while (iftxt);
cout << "Число символов, прочитанных в режиме text ="
<< countInTxt << endl;
return 0;
}
При открытии файла в текстовом режиме (без ios::binary):


каждая пара возврат каретки/первод строки при вводе
преобразуется в единственный символ перевода строки ( '\n' )
каждый перевод строки при выводе преобразуется в пару
1. Чтение/запись необработанных данных

Функция read позволяет извлекать из потока указанное число
символов, записывая их в буфер:
istream& istream::read( char* p, int len);
istream& istream::read( signed char* p, int len);
istream& istream::read(unsigned char* p, int len);
p - буфер для записи прочитанных символов
len - максимальное число символов, которые должны быть
прочитаны
1. Чтение/запись необработанных данных

Функция write позволяет поместить в поток указанное число
символов, из буфера:
istream& istream::write( char* s, int n);
istream& istream::write( signed char* s, int n);
istream& istream::write(unsigned char* s, int n);
s - буфер-источник
n - число символов, которые должны быть записаны
#include <iostream.h>
#include <fstream.h>
int i = 12345; long l=98765432; float f=4.536271;
double d=2.4e12;
char msg[]= "Hello";
const char bFname[]= "_IO.BIN";
const char tFname[]= "_IO.TXT";
int main(void)
{ // В текстовом режиме ofsream ofs( tFname);
if (ofs) // Проверить поток
{ ofs << i <<'\t' << l <<'\t' << f <<'\t' << d <<'\t' << msg << endl;
ofs.close(); }
ifsream ifs( tFname);
if (ifs) // Проверить поток
{ ifs >> i >> l >> f >> d >> msg; ifs.close(); }
// Теперь в бинарном
ofs.open(bName, ios::out | ios::binary);
if (ofs) // Проверить поток
{ ofs.write( (char*)&i, sizeof(i) );
ofs.write( (char*)&l, sizeof(l) );
ofs.write( (char*)&f, sizeof(f) );
ofs.write( (char*)&d, sizeof(d) );
ofs.write( msg, sizeof(msg) );
ofs.close();
}
ifs.open(bName, ios::out | ios::binary);
if (ifs)
// Проверить поток
{ ofs.read( (char*)&i, sizeof(i) );
ofs.read( (char*)&l, sizeof(l) );
ofs.read( (char*)&f, sizeof(f) );
ofs.read( (char*)&d, sizeof(d) );
ofs.read( msg, sizeof(msg) );
ifs.close();
}
return 0;
}
2. Чтение символа

Для извлечения из потока одиночного символа можно использовать
метод int istream::get( )
#nclude <iostream.h>
int main(void)
{ int ch;
cout << "Введите число за которым следует #:";
while ( (ch = cin.get() ) != '#' )
{ if ( ch == EOF ) break; cout << (char)ch; }
return 0;
}
2. Чтение символа
Можно применить также один из перегруженных вариантов get( )
istream& istream::get(char&);
istream& istream::get(signed char&);
istream& istream::get(unsigned char&);

Например:
#include <iostream.h>
int main(void)
{ char ch;
cout << "Введите число за которым следует #:";
while ( cin.get(ch) )
{ if ( ch == '#' ) break;
cout << (char)ch;
}
return 0;
}
3. Чтение строки

В библиотеке С++ имеются функции get и getline для чтения
символов вплоть до ограничителя. Они часто используются для
чтения строк
get

Метод istream& istream::get(char* _p, int _l, char _t) извлекает
символы из потока до тех пор, пока не
 будет найден ограничитель _t (по умолчанию \n)
 будет прочитано _l символов
 встретится коней файла.

Функция get не извлекает ограничитель из потока и не помещает его
в буфер
#include <iostream.h>
#include <limits.h>
const int MAX_LEN = 0x50;
int main(void)
{
char fname[MAX_LEN];
char lname[MAX_LEN];
cout << "Введите ваше имя:";
cin.get(fname, sizeof(fname)); // Прочитать имя с помощью get
cout << "Привет" << fname << endl;
cout << "Введите вашу фамилию:";
cin.ignore(INT_MAX, '\n'); // Очистить поток
//(ограничитель не был извлечен)
cin.get(lname, sizeof(lname)); // Проитать имя с помощью get
cout << "Привет" << lname << endl;
return 0;
}
getline

Этот метод тоже может быть использован для извлечения из потока
символов до тех пор, пока не будет найден ограничитель _t (по
умолчанию \n), не будет прочитано определенное число символов _l,
или не встретится конец файла
istream& istream::getline(char* _p, int _l, char _t)

Функция getline извлекает ограничитель, но не записывает его в
буфер.
#include <iostream.h>
const int MAX_LEN = 0x50;
int main(void)
{
char fname[MAX_LEN];
char lname[MAX_LEN];
cout << "Введите ваше имя:";
cin.getline(fname, sizeof(fname)); // Проитать имя с помощью get
cout << "Привет" << fname << endl;
cout << "Введите вашу фамилию:";
cin.getline(lname, sizeof(lname)); // Проитать имя с помощью get
cout << "Привет" << lname << endl;
return 0;
}
Другие часто используемые функции





Пропуск символов при вводе
Проверка счетчика извлечений
Заглядывание вперед
Позиционирование потока
Выяснение текущей позиции потока
Пропуск символов при вводе
Функция ignore
istream& istream::ignore(int n=1, int d=EOF);

Извлекает сиволы из потока (не более n символов, по умолчанию 1),
пока не встретится ограничитель d (по умолчанию EOF)
Проверка счетчика извлечений
Функция gcount
int istream::gcount( );

возвращает число символов, извлеченных последней функцией
неформатированного ввода.
Заглядывание вперед
Функция peek;
int istream::peek();


возвращает возвращает значение очередного символов, не извлекая
его из входного потока
функция возвращает EOF, если флаги состояния потока имеют
ненулевое значение
Позиционирование потока

Функции seekg и seekp могут использоваться для позиционирования
указателя извлечения/помещения соответственно входного и
выходного потока:
istream& istream::seekg(streampos);
istream& istream::seekg(streamoff, ios::seek_dir);
istream& istream::seekp(streampos);
istream& istream::seekp(streamoff, ios::seek_dir);
Выяснение текущей позиции потока

Функции tellg и tellp позволяют найти текущую позицию
соответственно входного и выходного потока
strempos istream::tellg( );
strempos ostream::tellp( );
Download