Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 157
Текст из файла (страница 157)
Файловые потоки Здесь представлена полная программа копирования одного файла в другой. Имена файлов берутся из аргументов командной строки: П!пс1ис!е <Тз1геат> и!пс!ис!е <сзЫ!!Ь> ооЫ еггог (сопз1 сбаг> р, сопят оба!> р2=") ( зЫ. сегг«р « "«р2 «'~п'; зЫ..ехй (1); ) ш'!таит (ш1 агус, сбаг' агуо[)) ( !у (агус!= Я) еггог (' неверное число аргументов ); зЫэ(Тз1геат 1гот (асуп[1)); ((/оп!крываем входной файл (Т ()Тгот) еггог ('не открываетсл входной файл*, агут(1)); зЫ: о)з1 еат 1о (асуп[2)). !!открываем выходнойфойл (Т (уо) еггог("не открывается венходной файл', агуо(2)) сбаг сб; юб|1е (!гот.уе1 (сй)) 1о ри1 (сб); (г" Щготео) () (( йо) еггог (" случилось чтото апранное ); Файл открывается для ввода созланием объекта класса (Тз1геат [входной файловый поток) и имеет имя, задаваемое аргументом.
Подобным же образом файл для вывода открывается созданием объекта класса оуз1геат [выходной файловый поток) и имеет имя, задаваемое аргументом. В обоих случаях мы проверяем состояние созданного объекта, чтобы узнать, благополучно ли открылся файл. Класс Ьаз!с оЯгеат объявлен в <Тз1геат>; 705 21.5. Файловые и строковые потоки !етр!а1е<с!азк СЬ, с!азз Тг= сбаг 1го!гк<СЬ» с!азз Ьазсс о/к!геат риЬйсЬатс !кггеат<СЬ, Тг ( риЫ!с. Ьак!с %1геат (); екр!ш1баз!с о~з1геат (солт сбаг'р, орелтоде т=ои1(!гипс! Ьатс/з!еби/<СЬ, Тг>* гдби/((сопзг; Ьоо(гз орел ((соле!, оо!с( орел (сопт сбаг*р, орелтоде т= ои! (!гипс~! ооиу с!озе ((; Класс Ьаис (/к1геат похож на Ьаяс о!к1геат за исключением того, что является производным от Ьаяс !к!гент и по умолчанию открыт для чтения.
Дополнительно стандартная библиотека предлагает класс Ьаис Ягеат, аналогичный Ьаис оЯгеат за исключением того, что он производится от Ьаз!с !оз1геат и по умолчанию может быть открыт как на запись, так и на чтение. Как обычно, для распространенных типов доступны определения типов 1дрег!еТ: !уреде/батс с/зггеат<сбаг> !/з1геат; !уреде/ бак!с о/кггеат<сбаг> %1геат; 1уреде/баас/к!сват<сбое>/кггеат; 1уреде/базис укггеат<взсбаг> т!/к1геат; 1уреде/баз!с о/к1геат -тсбаг> вз%1геат; 1уреде/ Ьак!с (к!сват<акбае> вук1геат; Класс Цз1геат похож на пук!гент за исключением того, что является производным от !к1геат и по умолчанию открывается на чтение. Кроме того стандартная библиотека предлагает класс/к!гент, похожий иа оук1геат за исключением того, что он производится от !оз1 еат и по умолчанию открывается на запись и чтение.
Второй аргумент в конструкторах файловых потоков описывает, как открывается файл: с!акз !ок баке ( риЫга //. 1урес!еУ!тр!етеи1айои с(елиедЗ орептоде; з1а!!с орелтоде арр, // добавление в конец а1е, // открытие и поиск канио файла Ыпагу, // ввод/вывод в двоичнол! виде !а ле текстовои) гл, // оглкрытие но тление ои1, // открытие на запись 1 иле; // урезать файл до нулевой длины Фактические значения орелтос!е и их смысл определяются при реализации. Насчет деталей сверьтесь, пожалуйста, с руководством по вашей системе — и повксперимснтируйте.
Комментарии должны дать некоторое представление о том, для чего предназначены соответствующие режимы открытия. Например, мы можем открыть файл, чтобы все добавлять еыу в конец: о!к!сват туз!сват (пате.с к1г ((, !оз Ьазе; арр~! Также можно открыть файл на запись и чтение: /к!геат д!с!!влагу ('солсогдапсе, !ок базес!л(юк Ьазесои1(; Глава 21. Потоки 706 21.5.2. Закрытие потоков Файл можно закрыть, явно вызвав с1ояе () данного потока: по!г!/(оя 1геа тй т уя!геа и!) ( туя1геат.с1ояе (); Однако это неявно делается деструк~ором потока.
Поэтому явный вызов с1ояе () требуется только в том случае, если файл нужно закрыть до конца области видимости, в которой объявлен дапньш поток. Тогда возникает вопрос как реализация может гарантировать, что предопределенные потоки сои1, ссп н сеп создадутся до их первого использования н закроются (только) после последнего? Естественно, для достижения этого различные реализации библиотеки потоков <1оя(геат> могут использовать различные прием»!. В конце концов, пользователю не должно быть видно, как именно реализованы детали. Здесь я привожу лишь олин прием, достаточно универсальный для того, чтобы гарантировать соответству!оший порядок выполнения конструкторов и деструкторов для глобальных объектов различных типов.
Реализации могут быть сделаны лучше за счет использования особенностей компилятора или компоновщика. Основная идея заклгочается в том, чтобы определить вспомогательный класс, который является счетчиком, отслеживающим, сколько раз <юя(геат> был включен в отдельно компилируемый исходный файл: с!аяя !оя Ьаяек1т1 ( я1ацс !а1 сопи!; риЬ1!с: 1а!1 (); -1а!! у; аатеярасе ( // в <!оя!а..ат>, оо котги на кождьв' файгь где есв!ь №и!с!!ше <!оя!геат> юя Ьаяе: 1а!! ютй, !а1!оя Ьаяек!аигсоиа1=0; Овстовьтьвкикой-нибудьфабл.с Каждая единица трансляции Я 9.1) объявляет свой собственный объект с именем !о!и!1. Конструктор для объектов юип1 использует гоя Ьаяес1п(1ссоип! как индикатор первого вызова, дабы гарантировать, что действительная инициализация глобальных объектов в библиотеке потоков ввода/вывода выполнится ровно олин раз: !оя Ьаяе:1а!Г:1а!1 () ( (! (соиа1++ == 0) (/'пя~циализоиги! сои!, сегг, с!а и т.
д. '/) И наоборот, деструктор для объектов гоя Ьаяе: 1п!1 использует 1оя Ьаяет!и!1;шоип1 как индикатор последнего вызова, дабы гарантировать, что потоки закро!отея: !оя Ьаяег1а!1 -1ац() ( ю!'( — соиа1== 0) (/"от!гота сои! (наарюгер. очистка буфера), сесе сга и т. д. */) 707 21.5. Файловые и строковые потоки Это универсальный прием для работы с библиотеками, требующими инициализации и очистки глобальных объектов. В системах, где весь код во время выполнения располагается в основной памяти, зтот прием почти не имеет ограничений.
В противном случае могут оказаться значительными затраты на занесение каждого объектного файла в основную намять для выполнения его инициализирующих функций. Глобальных объектов помере возможности следует избегать. Для классов, где каждая операция выполняет важную работу, чтобы гарантировать инициализацию, было бы разумно в каждой операции проверять индикатор первого вызова [как гоз Ьазе::Ьи1ссоип1). Однако зтот подход для потоков может оказаться чересчур дорогим. В функциях, считываклцих и записывающих один символ, затраты на индикатор первого вызова окажутся чрезмерными. 21.5.3.
Строковые потоки Поток можно прикрепить к строке. То есть мы можем считывать из строки я1»(ид и писать в такую строку при помощи предоставляемых потоками возможностей форматирования. Такие потоки называют з1г!идя!»еат, Они определены в <кз1геат>; гетр!иге<с!аяя СЬ, с!аяк Т» = сЬаг !гойя<СЬ» с!акз Ьак!с я1ппдя1геат . ри6!ге Ьиягс гокггеат<СЬ, Тг> ( риЬДс ехр!!с!! Ьак!с в!гтдз!геат (гоя Ьаяе:орелтойе т = ои1) !и); ехр!!сг! Ьак!с вгг!идзггеат (еоик16ак!с к!пну<СЬ>8, з, орептоиге т = оиг ) т); Ьак!с я1плд<СЬ> ягг () сопя!; О лозу<ение копии >1псд ооЫк1»(соля16ав!с к1г!пд<СЬ>йя)г //устиновка значения колпи в Ьая!с к1г!пдЬи/<СЬ, Тг,А>" »<16!у () сопя!; //полунетге укавитегя //на текущий гуайловий бугрер Класс Ьая!с (з1»!пдя1геат похож на Ьая!с я1ппдзугеат за исключением того, что он производится от Ьая!с !я! еат и по умолчанию открыт лля чтения.
Класс Ьая!с оз1ппдя1геат похож на Ьаз!с я1г!пдя1»ватка исключением того, что он производится от Ьая!с оз1геат и по умолчанию открыт для записи. Как обычно. функции обеспечивают основные специализации: 1урег!е~ьак!с гя!ппдз1геат<сЬаг> !к1ппдя!геат; 1урейе/Ьавге оя1г!лдкггеат<сЬаг> ок!ппдзггеат; 1урейе/Ьикге я1г!лдк1»еит<сЬаг> з!гтдя1геат, 1урег!е3 Ьатс !я!падя!»еат<госЬаг Г> го!к1г!пдкггеат; гурейеХЬикгг о<!ппдк!геит <теьаг 1> тотплдя!геат; !урег(е/Ьав!с кГ»!пдз!»еат<игсЬаг 1> пи!»!пдз1геат; Например, оя1ппдз1геат можно использовать для форматирования строки сообщения: тпид сотроке (!п1 п, сопя1 згг!пдй ея) ( ех1егп соля1 »Ьаг' кгс) тезяаде[]; оз1ппдв1геат оз1; оз! « 'ошибка (' «и « ') ' «зиу теяяаде[и) «" (коммент арий пользовигиеля.' «т «7, ге!игл оявяи (); Проверять на переполнение нет необходимости, поскольку оз1 расширяется автоматически.