WWW.DISSERS.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА

   Добро пожаловать!


Pages:     | 1 |   ...   | 14 | 15 || 17 |

void ifstream::open(const char *name, ios::openmode mode = ios::in);

void ofstream::open (const char * name, ios::openmode mode = ios::out | ios::trunc);

void fstream::open (const char * name, ios::openmode mode = ios::in | ios::out);

Здесь name – имя файла, mode – режим открытия файла. Параметр mode является перечислением и может принимать значения, указанные в табл. 8.

Таблица Режимы открытия и их назначение Режим открытия Назначение ios::in Открыть файл для чтения ios::out Открыть файл для записи ios::ate Начало вывода устанавливается в конец файла ios::app Окрыть файл для добавления в конец ios::trunc Усечь файл, то есть удалить его содержимое ios::binary Двоичный режим операций Режимы открытия файла представляют собой битовые маски, поэтому можно задавать два или более режима, объединяя их побитовой операцией ИЛИ. В следующем фрагменте кода файл открывается для вывода с помощью функции open():

ofstream ofs;

ofs.open(”FileName.txt”);

Обратим внимание, что по умолчанию режим открытия файла соответствует типу файлового потока. У потока ввода или вывода флаг режима всегда установлен неявно. Например, для потока вывода в режиме добавления файла можно вместо оператора ofstream ofs(”FName.txt”, ios::out | ios::app);

написать ofstream ofs(”FName.txt”, ios::app);

Между режимами открытия файла ios::ate и ios::app имеется небольшая разница.

Если файл открывается в режиме добавления, весь вывод в файл будет осуществляться в позицию, начинающуюся с текущего конца файла, безотносительно к операциям позиционирования в файле. В режиме открытия ios::ate (от английского ”at end”) можно изменить позицию вывода в файл и осуществлять запись, начиная с нее. Для потоков вывода режим открытия эквивалентен ios::out | ios::trunc, то есть можно опустить режим усечения файла. Однако для потоков вводавывода его нужно указывать явно. Файлы, которые открываются для вывода, создаются, если они еще не существуют.

Если открытие файла завершилось неудачей, объект, соответствующий потоку, будет возвращать 0:

if (!ofs){ cout << ”Файл не открыт\n”;} Проверить успешность открытия файла можно также с помощью функции-члена is_open(), имеющей следующий прототип:

int is_open() const;

Функция возвращает 1, если поток удалось связать с открытым файлом. Например, if (!ofs.is_open()){ cout << ”Файл не открыт\n”; return; } Если при открытии файла не указан режим ios::binary, файл открывается в текстовом режиме и после того, как файл успешно открыт, для выполнения операций ввода-вывода можно использовать операторы извлечения и вставки в поток. Для проверки, достигнут ли конец файла, можно использовать функцию ios::eof(), имеющую прототип int eof();

Завершив операции ввода-вывода, необходимо закрыть файл, вызвав функцию-член close() с прототипом void close():

ofs.close();

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

Рассмотрим пример, демонстрирующий файловый ввод-вывод с использованием потоков:

#include #include void main(){ int n = 50;

// Открываем файл для вывода ofstream ofs(”Test.txt”);

if (!ofs) {cout << ”Файл не открыт.\n”; return;} ofs << ”Hello!\n” << n;

// Закрываем файл ofs.close();

// открываем тот же файл для ввода ifstream file(”Test.txt”);

if (!file) {cout << ”Файл не открыт.\n”;

return;} char str[80];

file >> str >> n;

cout << str << ” ” << n << endl;

// Закрываем файл file.close();

} 27.6. Неформатируемый ввод-вывод Когда файл открывается в текстовом режиме, происходит следующее:

при вводе каждая пара символов ‘\r’ +’ \n’ (возврат каретки + перевод строки) преобразуется в символ перевода строки (‘\n’);

при выводе каждый символ перевода строки (‘\n’) преобразуется в пару ‘\r’ +’\n’ (возврат каретки + перевод строки).

Это не всегда удобно. Если необходимо использовать файл вывода для последующего ввода в программу (возможно, другую), лишние байты информации ни к чему. С этой целью система ввода-вывода предоставляет возможность осуществления неформатируемого вводавывода, то есть записи и чтения двоичной информации (иногда говорят – сырых данных). Для осуществления ввода-вывода в двоичном режиме нужно включить флаг ios::binary в параметр open_mode, передаваемый конструктору потока или функции open(). Чтение двоичной информации из файла осуществляется функцией read(), которая имеет следующие прототипы:

istream& read(char* s, int n);

istream& read(unsigned char* s, int n);

Здесь параметр s задает буфер для считывания данных, а параметр n – число читаемых символов.

Запись двоичных данных осуществляет функция-член write():

ostream& write(const char * s, int n);

ostream& write(const unsigned char * s, int n);

Эта функция получает n символов из буфера, адрес которого задан параметром s, и вставляет их в поток вывода. Рассмотрим пример.

#include #include void main() { int x = 255;

char str[80] = ”Тестирование двоичного ввода-вывода.”;

// Открываем файл для вывода в двоичном режиме ofstream ofs(”Test.txt”);

if (!ofs) { cout << ”Файл не открыт.\n”; return; } ofs.write((char*)&x, sizeof(int));

ofs.write((char*)&str, sizeof(str));

ofs.close();

// Открываем файл для вывода в двоичном режиме ifstream ifs(”Test.txt”);

if (!ifs) { cout << ”Файл не открыт.\n”; return; } ifs.read((char*)&x, sizeof(int));



ifs.read((char*) str, sizeof(str));

cout << x << ‘\n’ << str << ‘\n’;

} 27.7. Часто применяемые функции Помимо уже описанных функций, библиотека ввода-вывода C++ содержит широкий набор различных функций. Здесь мы приведем лишь некоторые, наиболее часто употребляемые из них. Большинство этих функций используется для неформатируемого ввода-вывода.

Для извлечения символа из потока можно использовать функциючлен get() потока istream. Она имеет следующие прототипы:

int get();

istream& get(signed char*, int len, char delim= '\n');

istream& get(unsigned char*, int len, char delim= '\n');

istream& get(unsigned char &);

istream& get(signed char &);

istream& get(streambuf &, char delim= '\n');

Функция get() в первой форме возвращает код прочитанного символа или -1, если встретился конец файла ввода (ctrl/z).

Приведем пример использования функции get ():

#include void main(){ char ch;

cout << ”Введите число. ” << ”Для завершения ввода нажмите :”;

while (cin.get(ch)){ // Проверка на код клавиши if (ch = = ‘\n’) break;

} return;

} Для вставки символа в поток вывода используется функция put() с прототипом ostreaiu& put(char ch). Функция get () может также использоваться для чтения строки символов. В этом случае используются ее варианты, в которых эта функция извлекает из входного потока символы в буфер str, пока не встретится символ-ограничитель delim (по умолчанию – перевод строки) или не будет прочитано (len-1) символов, или не будет прочитан признак конца файла. Сам символограничитель не извлекается из входного потока.

Ввиду того, что функция get() не извлекает из входного потока символ-ограничитель, она используется редко. Гораздо чаще используется функция getline(), которая извлекает из входного потока символограничитель, но не помещает его в буфер. Она имеет следующие прототипы:

istream& getline (char* str, int len, char delim);

istream& getline(char * str, int len);

Здесь параметры имеют те же назначения, что и в функции get().

Функция gcount() (с прототипом int gcount()const;) возвращает число символов, извлеченных из потока последней операцией неформатируемого ввода (то есть функцией get(), getline() или read()).

Рассмотрим пример, в котором используются две последние функции:

#include void main(){ char *name;

int len = 100;

int count = 0;

name = new char[len];

cout << ”Введите свое имя:”;

cin.getline(name, len);

count = cin.gcount();

// Уменьшаем значение счетчика на 1, так как // getline() не помещает ограничитель в буфер.

cout << ”\nЧисло прочитанных символов: ” << count – 1;} Для того, чтобы пропустить при вводе несколько символов, используется функция ignore():

istream & ignore(int n = l, int delim = EOF);

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

Символ-ограничитель извлекается из входного потока.

Функция peek(), имеющая прототип int peek(), позволяет ”заглянуть” во входной поток и узнать следующий вводимый символ. При этом сам символ из потока не извлекается.

С помощью функции putback() (с прототипом istream &putback(char ch);) можно вернуть символ ch в поток ввода.

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

Она неявно используется манипулятором endl. Этот манипулятор вставляет в поток символ перевода строки и очищает буфер. Таким образом, оператор cout << endl;

эквивалентен следующим:

cout << ‘\n’; cout.flush();

Функция rdbuf() позволяет получить указатель на связанный с потоком буфер. Эта функция имеет прототип streambuf * rdbuf() const;

Наконец, функция setbuf() с прототипом void setbuf(char * buf, int n) позволяет связать с потоком другой буфер. Здесь buf – указатель на другой буфер длины n.

27.8. Файлы с произвольным доступом Произвольный доступ в системе ввода-вывода реализуется с помощью функций seekg() и seekp(), используемых для позиционирования, соответственно, входного и выходного потока. Каждая из них имеет по два прототипа:

istream& seekg(long pos);

istream& seekg(long pos, seek_dir dir);

ostream& seekp(long offset);

ostream& seekp(long offset, seek_dir dir);

Здесь параметр pos задает абсолютную позицию в файле относительно начала файла. Параметр offset задает смещение в файле, а параметр dir – направление смещения, которое может принимать значения в соответствии с определением из класса ios:

enum seek_dir { beg, cur, end };

Здесь константы перечисления определяют:

ios::beg – смещение от начала файла, ios::cur – смещение относительно текущей позиции, ios::end – смещение от конца файла.

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

Получить текущее значение позиции в потоке ввода или вывода можно с помощью функций tellg() и tellp(), соответственно. Эти функции имеют следующие прототипы:

long tellg ();

long tellp();





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

#include #include void main(int argc, char* argv[]){ int size = 0;

if (argc > 1){ const char *FileName = argv[1];

ofstream of;

of.open( FileName, ios::binary );

for(int i = 0; i<100; i++) of.put ((char)(i+27));

of.close();

ifstream file;

file.open(FileName, ios::in | ios::binary);

if (file){file.seekg(0, ios::end);

size = file.tellg();

if (size < 0){ cerr << FileName << ” не найден.”; return; } cout << FileName << ” size = ” << size<

}} else cout << ”Вы не задали имя файла.”;

} Программа выводит на экран длину заданного файла.

27.9. Опрос и установка состояния потока Класс ios поддерживает информацию о состоянии потока после каждой операции ввода-вывода. Текущее состояние потока хранится в объекте типа iostate, который объявлен следующим образом:

typedef int iostate;

Состояния потока являются элементами перечислимого типа io_state, который может иметь значения, представленные в табл. 9.

Таблица Состояния потока и их значения Состояние Значение Goodbit Ошибок нет Eofbit Достигнут конец файла Failbit Имеет место ошибка форматирования или преобразования Badbit Имеет место серьезная ошибка Для опроса и установки состояния потока можно использовать функции-члены класса ios. Имеется два способа получения информации о состоянии операции ввода-вывода. Во-первых, можно вызвать функцию rdstate(), имеющую прототип iostate rdstate() const.

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

int good() const;

int eof() const;

int fail() const;

int bad() const;

Каждая из этих функций возвращает 1, если установлен соответствующий бит состояния (точнее, функция fail() возвращает 1, если установлен бит failbit или badbit).

Если прочитано состояние, которое сигнализирует об ошибке, его можно сбросить с помощью функции clear ():

void clear(iostate state = ios::goodbit);

Установить нужное состояние можно с помощью функции setsfate():

void setstate(iostate state);

Кроме перечисленных функций, класс ios содержит функцию приведения типа operator void*() const; (она возвращает NULL, если установлен бит badbit) и перегруженный оператор логического отрицания int operator !() const; (он возвращает 1, если установлен бит badbit). Это позволяет сравнивать выражения, в которые входит поток или его отрицание с нулем, то есть писать выражения вида:

while(!strm.eof()) {... } Следующий пример иллюстрирует получение информации о состоянии ввода-вывода.

#include #include int main(int argc, char* argv[]) { char c;

if (argc > 1){ ifstream ifs(argv[1]);

if (!ifs){ cout << ”Файл не открыт\n”; return 1; } while (ifs.eof()) { ifs.get(c);

// Контроль состояния потока if (ifs.fail ()) {cout << ”Ошибка \n”; break;

} cout << с;

} ifs.close();

} return 0;

} В этом примере осуществляется ввод символов из файла, заданного в командной строке при запуске программы. Если при извлечении символов встречается ошибка, чтение прекращается и выводится сообщение об этом.

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

class Date { public:

Date(int d, int m, int y);

Date(const tm & t);

Date();

private:

tm tm_date;

};

Этот класс содержит член типа tm, который представляет собой структуру для хранения даты и времени, определенную в заголовочном файле time.h. Чтобы осуществить ввод-вывод пользовательского типа данных, какими являются объекты класса Date, нужно перегрузить операции извлечения и вставки в поток для этого класса. Приведем соответствующее объявление класса Date:

class Date { tm tm_date;

friend istream& operator>>(istreamfi &is, Date txt);

friend ostream& operator<<(ostream& os, const Date& txt);

public:

Date(int d, int m, int y);

Date(tm t);

Date();

tm tm_date;

friend istream& operator>>(istreamfi &is, Date txt);

friend ostream& operator<<(ostream& os, const Date& txt);

};

Реализуем операции извлечения и вставки для объектов класса Date.

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

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

istream.& operator>>(istream& is, Date& txt){ is >> txt.tm_date.tm_mday;

is >> txt.tm_date.tm_mon;

is >> txt.tm_date.tm_year;

return is;

Pages:     | 1 |   ...   | 14 | 15 || 17 |










© 2011 www.dissers.ru - «Бесплатная электронная библиотека»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.