246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 84
Текст из файла (страница 84)
Использование объектов ofstream требует включения впрограммуфайлазаголовкаfstream.h.Примечание:Поскольку fstream содержит в себе iostream.h, нет необходимости вотдельномвключениифайлаiostream.h.СостоянияусловийОбъектами iostream поддерживаются флаги, отражающие состояние ввода и вывода.Значениекаждогоизэтихфлаговможнопроверитьспомощьюфункций,возвращающихTRUEилиFALSE:eof(),bad(),fail()иgood().Функцияeof()возвращаетзначениеTRUE,есливобъектеiostreamвстретилсясимволEOF(endoffile—конецфайла).Функцияbad()возвращаетзначениеTRUEприпопыткевыполнитьошибочнуюоперацию.Функцияfail()возвращаетзначениеTRUEкаждый раз, когда это же значение возвращает функция bad(), а также в тех случаях, когдаоперацияневыполнимавданныхусловиях.Наконец,функцияgood()возвращаетзначениеTRUE,когдавсеидетхорошо,т.е.все.остальныефункциивозвращаютзначениеFALSE.Открытиефайловдляввода-выводаДля открытия файла myfile.cpp с помощью объекта ofstream нужно объявить экземплярэтогообъекта,передавемувкачествепараметраимяфайла:ofstreamfout("myfile.cpp");Открытиефайладлявводавыполняетсяаналогичнымобразом,затемисключением,чтодляэтогоиспользуетсяобъектifstream:ifstreamfin("myfile.cpp");Обратитевнимание,чтоввыраженияхзадаютсяименаобъектовfoutиfin,которыеможноиспользоватьтакже,какобъектыcoutиcinсоответственно.Оченьважнымметодом,используемымвфайловыхпотоках,являетсяфункция-членclose().Каждый создаваемый вами объект файлового потока открывает файл для чтения или записи(или и для того и другого сразу).
По завершении работы файл необходимо закрыть с помощьюфункцииclose(),чтобывпоследствиинеповредитьегоизаписанныевнемданные.После связывания объектов потока с соответствующими файлами их можно использоватьтак же, как остальные объекты ввода-вывода. Пример использования объектов для обменаданнымисфайламипоказанвлистинге16.16.Листинг16.16.Открытиефайладлячтенияизаписи1:#include<fstream.h>2:intmain()3:{4:charfileName[80];5:charbuffer[255];//длявводаданныхпользователем6:cout<<"Fileпаше:";7:cin>>fileName;8:9:ofstreamfout(fileName);//открытиефайладлязаписи10:fout<<"Thislinewrittendirectlytothefile...\n";11:cout<<"Entertextforthefile:";12:cin.ignore(1,'\n');//пропускаетсимволразрывастрокипослеименифайла13:cin.getline(buffer,255);//принимаетданные,введенныепользователем,14:fout<<buffer<<"\n";//изаписываетихвфайл15:fout.close();//закрываетфайл,послечегоеговновьможнооткрыть16:17:ifstreamfin(fileName);//открываетсятотжефайлдлячтения18:cout<<"Here'sthecontentsofthefile:\n";19:charch;20:while(fin.get(ch))21:cout<<ch;22:23:cout<<"\n***Endoffilecontents.***\n";24:25:fin.close();//незабудьзакрытьфайлвконцепрограммы26:return0;27:}Результат:Filename:test1Entertextforthefile:Thistextiswrittentothefile!Here'sthecontentsofthefile:Thislinewrittendirectlytothefile...Thistextiswrittentothefile!***Endoffilecontents.***Анализ: В строке 4 создается массив для записи имени файла, а в строке 5 — еще одинмассив для временного хранения информации, вводимой пользователем.
В строке 6пользователюпредлагаетсяввестиимяфайла,котороезаписываетсявмассивfileName.Встроке9 создается объект ofstream с именем fout, который связывается с введенным ранее именемфайла. В результате происходит открытие файла. Если файл с таким именем уже существует,содержащаясявнеминформациябудетзамещена.Строкой10введенныйтекстзаписываетсяпрямовфайл,австроке11пользователювновьпредлагается ввести новый текст. Символ разрыва строки, оставшийся в буфере после вводаимени файла, удаляется строкой 12, после чего все введенные пользователем данныезаписываются в массив в строке 13.
Введенный текст записывается в файл вместе с символомразрывастроки,азатемвстроке15этотфайлзакрывается.В строке 17 файл открывается заново, но в этот раз для чтения, и его содержимоепосимвольновводитсявпрограммувстроках20—21.НастройкаоткрытияфайлаобъектомofstreamПо умолчанию при связывании объекта ofstream с именем файла создается новый файл суказаннымименем,еслитаковойнесуществует,илиудаляетсясодержимоеужесуществующегофайла с таким же именем. Чтобы изменить установки по умолчанию, используется второйаргументконструктораобъектаofstream.Длявторогоаргументаможноустанавливатьследующиеконстантныезначения:•ios::app—добавляетданныевконецфайлавместоудалениявсегосодержимогофайла;•ios::ate—переводитточкувводавконецфайла,ноувасестьвозможностьвводитьновыеданныевлюбомместефайла;• ios::trunc — устанавливается по умолчанию; полностью удаляет (отбрасывает) текущеесодержимоефайла;•ios::nocreate—еслифайлнесуществует,операцияоткрытияневыполняется;•ios::noreplace—еслифайлужесуществует,операцияоткрытияневыполняется.Именаконстантявляютсяаббревиатурамивыполняемыхдействий:app—apend(добавить),ate—atend(вконец),trunc—truncate(отбросить)ит.п.Листинг 16.17 является модификацией листинга 16.16 с установкой опции добавленияданныхвфайлприегоповторномоткрытии.Листинг16.17.Добавлениеданныхвконецфайла1:#include<fstream.h>2:intmain()//возвращает1вслучаеошибки3:{4:charfileName[80];5:charbuffer[255];6:cout<<"Pleasere-enterthefilename:";7:cin>>fileName;8:9:ifstreamfin(fileName);10:if(fin)//файлужесуществует?11:{12:cout<<"Currentfilecontents:\n";13:charch;14:while(fin.get(ch))15:cout<<ch;16:cout<<"\n***Endoffilecontents.***\n";17:}18:fin.close();19:20:cout<<"\nOpening"<<fileName<<"inappendmode...\n";21:22:ofstreamfout(fileName,ios::app);23:if(!fout)24:{25:cout<<"Unabletoopen"<<fileName<<"forappending.\n";26:return(1);27:}28:29:cout<<"\nEntertextforthefile:";30:cin.ignore(1,'\n');31:cin.getline(buffer,255);32:fout<<buffer<<"\n";33:fout.close();34:35:fin.open(fileName);//переопределениесуществующегообъектаfin!36:if(!fin)37:{38:cout<<"Unabletoopen"<<fileName<<"forreading.\n";39:return(1);40:}41:cout<<"\nHere'sthecontentsofthefile:\n";42:charch;43:while(fin.get(ch))44:cout<<ch;45:cout<<"\n***Endoffilecontents.***\n";46:fin.close();47:return0;48:}Результат:Pleasere-enterthefilename:test1Currentfilecontents:Thislinewrittendirectlytothefile...Thistextiswrittentothefile!***Endoffilecontents.***Openingtest1inappendmode...Entertextforthefile:Moretextforthefile!Here'sthecontentsofthefile:Thislinewrittendirectlytothefile...Thistextiswrittentothefile!Moretextforthefile!***Endoffilecontents.***Анализ: Пользователю вновь предлагается ввести имя файла, после чего в строке 9создаетсяобъектфайловогопотокаввода.Встроке10проверяетсяналичиенадискеуказанногофайла и, если он уже существует, его содержимое выводится на экран строками 12—16.Обратитевниманиенато,чтовыражениеif(fin)аналогичноif(fin.good()).Файл ввода закрывается и снова открывается, однако теперь в режиме добавления (строка22).
После этого открытия (как, впрочем, после каждого открытия) выполняется проверкаправильности открытия файла. В этом случае условие if(!fout) подобно условию if (fout.fail()).Пользователюпредлагаетсяввеститекст,послечеговстроке33файлзакрывается.Наконец, как и в листинге 16.16, файл открывается в режиме чтения, но в этом случае ненужно повторно объявлять объект fin.
Он просто связывается с тем же именем файла. Послепроверкиправильностиоткрытияфайлавстроке36содержимоефайлавыводитсянаэкранионокончательнозакрывается.Рекомендуется:Постоянно проверяйте правильность открытия файла. Повторноиспользуйтеужесуществyющиeoбъeктыifstreamиofstream.Закрывайтевсеобъектыfstreamпозавершенииработысними.Нерекомендуется:Непытайтесьзакрытьилипереопределитьобъектыcinиcout.ДвоичныеитектовыефайлыНекоторые операционные системы, например DOS, различают текстовые и двоичныефайлы.
В первых все данные хранятся в виде текста (в кодах ASCII). Числовые значения,например54321,хранятсяввидестроки('5','4','3','2','1').Возможноэтонесовсемудобно,однакоупрощаетсчитываниеинформациимногимипростымипрограммамидляDOS.Чтобы помочь файловой системе отличить текстовый формат файла от двоичного, языкпрограммирования C++ предоставляет флаг ios::binary. Во многих системах этот флагигнорируется, поскольку все данные хранятся в двоичном формате. А в некоторых закрытыхсистемахэтотфлагвообщезапрещенинеподдаетсякомпиляции!Вдвоичныхфайлахмогутхранитьсянетолькочислаистроки,ноицелыеинформационныеструктуры.Весьблокданныхможновывестисразу,используяметодwrite()объектаfstream.Записав данные с помощью write(), можно возвратить эти данные обратно с помощьюметодаread().Вкачествепараметраэтифункции-членыожидаютполучитьуказательнасимвол,поэтому перед использованием функции необходимо привести адрес класса к указателю настрокусимволов.Второй аргумент этих функций задает количество записываемых символов.
Это значениеможно определить с помощью функции sizeof(). Запомните, что записываются данные, а неметоды.Соответственноисчитываютсятолькоданные.Влистинге16.18показано,какзаписатьсодержимоеклассавфайл.Листинг16.18.Записьклассавфайл1:#include<fstream.h>2:3:classAnimal4:{5:public:6:Animal(intweight,longdays):itsWeight(weight),itsNumberDaysAlive(days){}7:~Animal(){}8:9:intGetWeight()const{returnitsWeight;}10:voidSetWeight(intweight){itsWeight=weight;}11:12:longGetDaysAlive()const{returnitsNumberDaysAlive;}13:voidSetDaysAlive(longdays){itsNumberDaysAlive=days;}14:15:private:16:intitsWeight;17:longitsNumberDaysAlive;18:};19:20:intmain()//returns1onerror21:{22:charfileName[80];23:24:25:cout<<"Pleaseenterthefilename:":26:cin>>fileName;27:ofstreamfout(fileName,ios::binary);28:if(!fout)29:{30:cout<<"Unabletoopen"<<fileName<<"forwriting.\n";31:return(1);32:}33:34:AnimalBear(50,100);35:fout.write((char*)&Bear,sizeofBear);36:37:fout.close();38:39:ifstreamfin(fileName,ios::binary);40:if(!fin)41:{42:cout<<"Unabletoopen"<<fileName<<"forreading.\n";43:return(1);44:}45:46:AnimalBearTwo(1,1);47:48:cout<<"BearTwoweight:"<<BearTwo.GetWeight()<<endl;49:cout<<"BearTwodays:"<<BearTwo.GetDaysAlive()<<endl;50:51:fin.read((char*)&BearTwo,sizeofBearTwo);52:53:cout<<"BearTwoweight:"<<BearTwo.GetWeight()<<endl;54:cout<<"BearTwodays:"<<BearTwo.GetDaysAlive()<<endl;55:fin.close();56:return0;57:}Результат:Pleaseenterthefilename:AnimalsBearTwoweight:1BearTwodays:1BearTwoweight:50BearTwodays:100Анализ:Встроках3-18объявляетсяклассAnimal.Встроках22-32создаетсяфайл,которыйоткрываетсядлявыводавдвоичномрежиме.Встроке34создаетсяобъектAnimalсозначениямипеременных-членов itsWeight = 50 и itsNumberDaysAlive = 100.