Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
При выполнении следующей программы сначала в файл записывается массив целых чисел, а затем он же считывается из файла.
// Использование функций read() и write(). #include < iostream> #include < fstream> using namespace std; Int main() { int n[5] = {1, 2, 3, 4, 5}; register int i; ofstream out(" test", ios:: out | ios:: binary); if(! out) { cout < < " He удается открыть файл."; return 1; } out.write((char *) & n, sizeof n); out.close(); for(i=0; i< 5; i++) // очищаем массив n[i] = 0; ifstream in (" test", ios:: in | ios:: binary); if(! in) { cout < < " He удается открыть файл."; return 1; } in.read((char *) & n, sizeof n); for(i=0; i< 5; i++) // Отображаем значения, считанные из файла. cout < < n[i] < < " "; in.close(); return 0; } Обратите внимание на то, что в инструкциях обращения к функциям read() и write() выполняются операции приведения типа, которые обязательны при использовании буфера, определенного не в виде символьного массива. Функция gcount() возвращает количество символов, считанных при выполнении последней операции ввода данных. Если конец файла будет достигнут до того, как будет считано num символов, функция read() просто прекратит выполнение, а буфер будет содержать столько символов, сколько удалось считать до этого момента. Точное количество считанных символов можно узнать с помощью еще одной функции-члена gcount(), которая имеет такой прототип. streamsize gcount(); Функция gcount() возвращает количество символов, считанных в процессе выполнения последней операции ввода данных. Обнаружение конца файла Обнаружить конец файла можно с помощью функции-члена eof(), которая имеет такой прототип. bool eof(); Эта функция возвращает значение true при достижении конца файла; в противном случае она возвращает значение false. Функция eof() позволяет обнаружить конец файла. В следующей программе для вывода на экран содержимого файла используется функция eof(). /* Обнаружение конца файла с помощью функции eof(). */ #include < iostream> #include < fstream> using namespace std; int main(int argc, char *argv[]) { char ch; if(argc! =2) { cout < < " Применение: имя_программы < имя_файла> "; return 1; } ifstream in(argv[1], ios:: in | ios:: binary); if(! in) { cout < < " He удается открыть файл."; return 1; } while(! in.eof()) { // использование функции eof() in.get(ch); if(! in.eof()) cout < < ch; } in.close(); return 0; } Пример сравнения файлов Следующая программа иллюстрирует мощь и простоту применения в C++ файловой системы. Здесь сравниваются два файла с помощью функций двоичного ввода-вывода read(), eof() и gcount(). Программа сначала открывает сравниваемые файлы для выполнения двоичных операций (чтобы не допустить преобразования символов). Затем из каждого файла по очереди считываются блоки информации в соответствующие буферы и сравнивается их содержимое. Поскольку объем считанных данных может быть меньше размера буфера, в программе используется функция gcount(), которая точно определяет количество считанных в буфер байтов. Нетрудно убедиться в том, что при использовании файловых С++-функций для выполнения этих операций потребовалась совсем небольшая по размеру программа. // Сравнение файлов. #include < iostream> #include < fstream> using namespace std; int main(int argc, char *argv[]) { register int i; unsigned char buf1[1024], buf2[1024]; if(argc! =3) { cout < < " Применение: имя_программы < имя_файла1> " < < " < имя_файла2> "; return 1; } ifstream f1(argv[1], ios:: in | ios:: binary); if(! f1) { cout < < " He удается открыть первый файл."; return 1; } ifstream f2(argv[2], ios:: in | ios:: binary); if(! f2) { cout < < " He удается открыть второй файл."; return 1; } cout < < " Сравнение файлов..."; do { f1.read((char *) buf1, sizeof buf1); f2.read((char *) buf2, sizeof buf2); if(f1.gcount()! = f2.gcount()) { cout < < " Файлы имеют разные размеры."; f1.close(); f2.close(); return 0; } // Сравнение содержимого буферов. for(i=0; i< f1.gcount(); i++) if(buf1[i]! = buf2[i]) { cout < < " Файлы различны."; f1.close(); f2.close(); return 0; } }while(! f1.eof() & & ! f2.eof()); cout < < " Файлы одинаковы."; f1.close(); f2.close(); return 0; } Проведите эксперимент. Размер буфера в этой программе жестко установлен равным 1024. В качестве упражнения замените это значение const-переменной и опробуйте другие размеры буферов. Определите оптимальный размер буфера для своей операционной среды. Использование других функций двоичного ввода-вывода Помимо приведенного выше формата использования функции get() существуют и другие ее перегруженные версии. Приведем прототипы для трех из них, которые используются чаще всего. istream & get(char *buf, streamsize num); istream & get(char *buf, streamsize num, char delim); int get(); Первая версия позволяет считывать символы в массив, заданный параметром buf, до тех пор, пока либо не будет считано num-1 символов, либо не встретится символ новой строки, либо не будет достигнут конец файла. После выполнения функции get() массив, адресуемый параметром buf, будет иметь завершающий нуль-символ. Символ новой строки, если таковой обнаружится во входном потоке, не извлекается. Он остается там до тех пор, пока не выполнится следующая операция ввода-вывода. Вторая версия предназначена для считывания символов в массив, адресуемый параметром buf, до тех пор, пока либо не будет считано num-1 символов, либо не обнаружится символ, заданный параметром delim, либо не будет достигнут конец файла. После выполнения функции get() массив, адресуемый параметром buf, будет иметь завершающий нуль-символ. Символ-разделитель (заданный параметром delim), если таковой обнаружится во входном потоке, не извлекается. Он остается там до тех пор, пока не выполнится следующая операция ввода-вывода. Третья перегруженная версия функции get() возвращает из потока следующий символ. Он содержится в младшем байте значения, возвращаемого функцией. Следовательно, значение, возвращаемое функцией get(), можно присвоить переменной типа char. При достижении конца файла эта функция возвращает значение EOF, которое определено в заголовке < iostream> . Функцию get() полезно использовать для считывания строк, содержащих пробелы. Как вы знаете, если для считывания строки используется оператор " > > " , процесс ввода останавливается при обнаружении первого же пробельного символа. Это делает оператор " > > " бесполезным для считывания строк, содержащих пробелы. Но эту проблему, как показано в следующей программе, можно обойти с помощью функции get(buf, num). /* Использование функции get() для считывания строк содержащих пробелы. */ #include < iostream> #include < fstream> using namespace std; Int main() { char str[80]; cout < < " Введите имя: "; cin.get (str, 79); cout < < str < < ''; return 0; } Здесь в качестве символа-разделителя при считывании строки с помощью функции get() используется символ новой строки. Это делает поведение функции get() во многом сходным с поведением стандартной функции gets(). Однако преимущество функции get() состоит в том, что она позволяет предотвратить возможный выход за границы массива, который принимает вводимые пользователем символы, поскольку в программе задано максимальное количество считываемых символов. Это делает функцию get() гораздо безопаснее функции gets(). Рассмотрим еще одну функцию, которая позволяет вводить данные. Речь идет о функции getline(), которая является членом каждого потокового класса, предназначенного для ввода информации. Вот как выглядят прототипы версий этой функции, istream & getline(char *buf, streamsize num); istream & getline(char *buf, streamsize num, char delim); Функция getline() представляет собой еще один способ ввода данных. При использовании первой версии символы считываются в массив, адресуемый указателем buf, до тех пор, пока либо не будет считано num-1 символов, либо не встретится символ новой строки, либо не будет достигнут конец файла. После выполнения функции getline() массив, адресуемый параметром buf, будет иметь завершающий нуль-символ. Символ новой строки, если таковой обнаружится во входном потоке, при этом извлекается, но не помещается в массив buf. Вторая версия предназначена для считывания символов в массив, адресуемый параметром buf, до тех пор, пока либо не будет считано num-1 символов, либо не обнаружится символ, заданный параметром delim, либо не будет достигнут конец файла. После выполнения функции getline() массив, адресуемый параметром buf, будет иметь завершающий нуль-символ. Символ-разделитель (заданный параметром delim), если таковой обнаружится во входном потоке, извлекается, но не помещается в массив buf. Как видите, эти две версии функции getline() практически идентичны версиям get (buf, num) и get (buf, num, delim) функции get(). Обе считывают символы из входного потока и помещают их в массив, адресуемый параметром buf, до тех пор, пока либо не будет считано num-1 символов, либо не обнаружится символ, заданный параметром delim. Различие между функциями get() и getline() состоит в том, что функция getline() считывает и удаляет символ-разделитель из входного потока, а функция get() этого не делает. Функция реек() считывает следующий символ из входного потока, не удаляя его. Следующий символ из входного потока можно получить и не удалять его из потока с помощью функции реек(). Вот как выглядит ее прототип. int peek(); Функция peek() возвращает следующий символ потока, или значение EOF, если достигнут конец файла. Считанный символ возвращается в младшем байте значения, возвращаемого функцией. Поэтому значение, возвращаемое функцией реек(), можно присвоить переменной типа char. Функция putback() возвращает считанный символ во входной поток. Последний символ, считанный из потока, можно вернуть в поток, используя функцию putback(). Ее прототип выглядит так. istream & putback(char с); Здесь параметр с содержит символ, считанный из потока последним. Функция flush() сбрасывает на диск содержимое файловых буферов. При выводе данных немедленной их записи на физическое устройство, связанное с потоком, не происходит. Подлежащая выводу информация накапливается во внутреннем буфере до тех пор, пока этот буфер не заполнится целиком. И только тогда его содержимое переписывается на диск. Однако существует возможность немедленной перезаписи на диск хранимой в буфере информации, не дожидаясь его заполнения. Это средство состоит в вызове функции flush(). Ее прототип имеет такой вид. ostream & flush(); К вызовам функции flush() следует прибегать в случае, если программа предназначена для выполнения в неблагоприятных средах (для которых характерны частые отключения электричества, например). Произвольный доступ До сих пор мы использовали файлы, доступ к содержимому которых был организован строго последовательно, байт за байтом. Но в C++ также можно получать доступ к файлу в произвольном порядке. В этом случае необходимо использовать функции seekg() и seekp(). Вот их прототипы. istream & seekg(off_type offset, seekdir origin); ostream & seekp(off_type offset, seekdir origin); Используемый здесь целочисленный тип off_type (он определен в классе ios) позволяет хранить самое большое допустимое значение, которое может иметь параметр offset. Тип seekdir определен как перечисление, которое имеет следующие значения. Функция seekg() перемещает указатель, " отвечающий" за ввод данных, а функция seekp() — указатель, " отвечающий" за вывод. В С++-системе ввода-вывода предусмотрена возможность управления двумя указателями, связанными с файлом. Эти так называемые cin- и put-указатели определяют, в каком месте файла должна выполниться следующая операция ввода и вывода соответственно. При каждом выполнении операции ввода или вывода соответствующий указатель автоматически перемещается в указанную позицию. Используя функции seekg() и seekp(), можно получать доступ к файлу в произвольном порядке. Функция seekg() перемещает текущий get-указатель соответствующего файла на offset байт относительно позиции, заданной параметром origin. Функция seekp() перемещает текущий put-указатель соответствующего файла на offset байт относительно позиции, заданной параметром origin. В общем случае произвольный доступ для операций ввода-вывода должен выполняться только для файлов, открытых в двоичном режиме. Преобразования символов, которые могут происходить в текстовых файлах, могут привести к тому, что запрашиваемая позиция файла не будет соответствовать его реальному содержимому. В следующей программе демонстрируется использование функции seekp(). Она позволяет задать имя файла в командной строке, а за ним — конкретный байт, который нужно в нем изменить. Программа затем записывает в указанную позицию символ " X" . Обратите внимание на то, что обрабатываемый файл должен быть открыт для выполнения операций чтения-записи. /* Демонстрация произвольного доступа к файлу. */ #include < iostream> #include < fstream> #include < cstdlib> using namespace std; int main(int argc, char *argv[]) { if(argc! =3) { cout < < " Применение: имя_программы " < < " < имя_файла> < байт> "; return 1; } fstream out(argv[1], ios:: in | ios:: out | ios:: binary); if(! out) { cout < < " He удается открыть файл."; return 1; } out.seekp(atoi(argv[2]), ios:: beg); out.put('X'); out.close(); return 0; } В следующей программе показано использование функции seekg(). Она отображает содержимое файла, начиная с позиции, заданной в командной строке. /* Отображение содержимого файла с заданной стартовой позиции. */ #include < iostream> #include < fstream> #include < cstdlib> using namespace std; int main(int argc, char *argv[]) { char ch; if(argc! =3) { cout < < " Применение: имя_программы " < < " < имя_файла> < стартовая_позиция> "; return 1; } ifstream in(argv[1], ios:: in | ios:: binary); if(! in) { cout < < " He удается открыть файл."; return 1; } in.seekg(atoi(argv[2]), ios:: beg); while(in.get (ch)) cout < < ch; return 0; } Функция tellg() возвращает текущую позицию get-указателя, а функция tellp() — текущую позицию put-указателя. Популярное:
|
Последнее изменение этой страницы: 2016-03-17; Просмотров: 1294; Нарушение авторского права страницы