Искусство программирования на Си (984073), страница 20
Текст из файла (страница 20)
Это очевидный аналог функции райн(, нсполь- ных С совпадает с размером данных в файле, то в этом ( зуюший цикл для расширения размера величины йше ( случае можно прочесть или записать все целые величитс. Дробная часть возвращается в виде числа с плаваюдо шести байтов: ны сразу, используя функции Ггеа«> илн йнп(е, и переставлять байты только по необходимости. Например, зпе е, в = 0; щей точкой нз диапазона от 0 до 1. Затем она передается «1С рпеес е(С«е С С, ЛГЬВ оер) в другую функцию из библиотеки <ша(Ь.Ь> — >бехр— ( массив агг, содержащий 2-байтовые целые величины, вассу = угехр(Г, се)1 лля умножения сс на 2", в результате чего дробная часть 1пг 11 можно записать с помощью программы, подобной при- 10 вапг( < 0) Гог(1 01 1 < 61 1++) 10(валей 0) сдвигается влево на 24 бита, и се можно рассматривать ( в = 1; вапгд = -вапгу; ( как целое число.
Поскольку бит старшего порядка в нор- рпсс(с с Ох((, оур); Осг«эае Вхпвнохам вапС1 1«)ехр(валет, 24)1 мированной ненулевой дробной части всегда равен ), С» О; ввар2Ьуеев(агг, па)) ВаПС1 Ьи (1Ь « 23)1 форматы 1ЕЕЕ-754 нс сохраняют его, поэтому мы очи- ) >и затираем веяввув аачапьвув едвввцу */ шасм этот бит. Мы располагаем биты показателя степссмг1се(агг, 2, па, охр); ни и знака на соответствующих позициях и в конце за- Далее представлена соответствующая функция для где функция ьмвруЬ>те< представляет собой что-то вроде ((ппв1дпес 1опд)(е«12б б Охгг) « 21 ) писываем четыре байта. о б й чтения (Ьве (' тоха амарльуеее(исса *Ьпх, еьхе С и> Данная версия функции рв(йоа( нс является полной, ( Спе деееьма (С' е С *Ср, Лтсл *хдр) рпес(вапС1 б Охуг, огр); поскольку она не манипулирует ни ненормированнырпес((аапС1 » 8) б Ох((, отр)« ми числами, нн бесконечными величинами.
На %еЬ( ппа1дпес сЬаг *р = Ьпс« Свр) с«.ве с в«хе С 11 рагс((вапг) » )б) с Ох(Г, о(р); сайте издательства "ДиаСофт" содержится более полная сьаг ьп((б) 1 рагс((вапС1» 24) с ОхИ, оур); ) реализация этой функции. 1пс свр = Р1«1; Ннжс приведена реализация парной функции хранение и или«ененне данных //е/и<митр<нные язык С' Часть 1 Глава 6 Файлы, в качестве разделителей использующие символы пробела или табуляции $1п<1мце <аецдея.и> е(ве1вде <<суре.Ь> ,"е '"~'„. ","".,:...«' '»„.,:,'"' .;,"" е", ° ' " „",'" ':„' г,", йе, м" '";.
*.; Гтс«' „;,. *,' ',*' 'с',': З я"',","е ,';„.;„,,„.',л,ж" ;1",,')е~'.:.:,:-.;е", -",:р„.--...~ 'д";"„.:, ',', ".;:,...";>,',,',.=,','...",';"е'л( / и ",.~ ~„"*,",,",'- *й> ф',.'",ы*:-,!,-'' я' *и " *' ', '' '„' '"',„","', и дл, я'*,' '~,'-:,',:,З '"-.* .. ~,:*.*'„,:«;;,,;"!' ',,',;;.' *'-;."'-, '* "'- *." ее е., У .',".'.;,, ЬЬ и"ч,*,*'„'...,""-"~;:;и".,Х'";;"-"«.',," .;...'.',","-,"'"'* '-.*;,'.гда" (ел": ;:;:,;:„~!',,~, '.',,";",::"',;,;;.",.
- '«'»-". (:и'а "..',',;:.':,: В<1:„'е --,", ';;, -/ з.-' '*ч ",'и'."; "';*.;=:";-"м.с„'.,:;,", л.уеы я ":.<зфзх:.э . -:"',"", -', Г;'; ";,""„,,' ',,д д ( ';:::.;:Ь',"".;;:,'.'„",-,',!>-,)ч/;."Ь.,;:;!'-,,::,":,";. '~,.:;:'= ые",.„"=";,!л,ич;",з"; '1',,"'.;.;.,'.'„!1;-,"':=",'.,;.;!;,-;:!' , "~ ,"„,',' З[Ххь йл ',' '; ' ' '„...Дс";,,"...Р";,, е)', ' "~ с'„""'*,;",„;";;"„, '".,', .ле."...';1>';" ется компьютером. Стиль программирования, требуюший, чтобы подобные установки (размер типа, порядок байтов и т.д.) были точно определены, полностью противопоказан лля поддержания персносилюсти, поэтому его следует избегать. Другой аспект переносимого определения двоичных файлов (т.е. независимога определения порядка байтов, как части формата файла данных) состоит в том, что если файл данных и записывается, и считывается на компьютерах с "неправильным порядком", данные, в конце концов, будут переставлены два раза.
Можно л~инимизировать лишние перестановки за счет усложнения процедуры: при записи файлов ланных всегда использовать внутренний порядок бантов записываюшсго компьютера, но при этом помечать файл данныл таким образом, чтобы считываюшая программа знала, какой именна порядок байтов использован в данном конкретном файле, и в соответствии с эзилз проводила или не провалила перестановку.
Например. если была записана,пйстоянная 2тбайтовая,ясли (ича Ох0102 ил)1 Возможно, наиболес обшсупотребитсльным и широко применяемым, особенно в среде [ЛЧ)Х, является текстовый формат с колонками цифр, разделенных пробелами. Очень полезно было бы написать абслуживаюшую программу, которая может оперировать разделенными пробелами полями, поскольку, в конце концов, она булст более полезной во многих случаях, чем собственно чтение файлов данных.
Одной из частей такой обслуживаюшей программы является приведенная нике функция, разделяюшая строку пробелами на серию "слов". Эта функция выполняет работу, полобную той, которую выполняет библиотечная функция а(г(ой, но с другим интерфейсом. мЬ1)е((дага(11яе. взееа((11ае), 1гр) 1!= Иаьд) асгасру(а->лег, магда[ 1), азяаог(а->век))! ( 1((е1лае == '$') сове1вве; /* веапозааввме паяя агворвруямся */ ам деемаге)а(11ва, магда, Э); 1((ам < 3) саве1аве; 11(ва >= ИАХАЮИТ) Ьгеа)г; Если упорялочивать колонки, разделенные произв.л = ага1(маге)а[0!); вольными символами пробела, то нельзя допустить суа.Г = аеа((магда[ 1!)Г шествование любых пробелов внутри произвольных 1( ( (Р = аеГГСЬГ(МОГЕ(а[11 '(а' ) ) 1= ВЦЬЬ) колонок. (Трюк, использованный в прелылушем прилеер- (аг рс, можно применять только для последней колонки.) аегвсру(а.агг, маге)а[2], агава/(а.аег)); ваггау[аае+! = а ° Другой подход заключается в выборе только одного 1 конкретного разделителя и использовании его в слиничнол~ экземпляре для отделения кажлой колонки.
Очень В эту программу привнесена также несколько тончасто в качестве разделителя выбирают символ табулякостсй: строки, начинаюшисся с символа я, рассматриции; тскстовыс файлы данных, содержашие разлеленваются как комлеентарии и пропускаются; пропускаютныс символами табуляции поля, часто называют ТОР ся также пустые строки. (гаЬ-е(с1пп((ее( йеы). Если проводить строгую политику Как упоминалось ранее, при записи строк в текстоо~деления каждан колонки только символом табуляции, вые файлы часто нужно проявлять осторожность, если то тогда внутри любой колонки можно допустить суше- строки могут содержать пробелы или другис разлслитествование других пробелов.
При этом также оказываетли текста. Что касается данного примера, то что прайя рнпзмйкллым обрнбвтыяйть пррбеаы венауйве н я кон, Пергсиотремвналзнк С Щ~ —— Часть! Хранение и лгкмчглигдилннх Глава б чогс нггеесо1в(сваг 'со1в[), (ое псо1в, блемы полей, солар кащих разделитель. В данном слу- кй[оа >= пагг) ~ае не учитывается возможность того, что поле величи- гетогл ла; ны можст содержать запятую. Если одно из разделенгпс ных запятой полей заключено в двойные кавычки, то 11(*р -= "') (ог(1 = 0; з < асо1в; з++) предполагается, что занятая внутри этого поля являет- ( ся нс разделителем, а частью поля данных.
Г[оскольлу 1одоосе = ТВОЕ; Гог(р = со1в[з]; 'р (= '10'; р++) двойные кавычки используются как снециачьный сим- соо11ооез / орооускаем кавычка */ вол, нужно отслеживать возможность того, что поле 11(тр 1= аа)1В ЬЬ гр 1= ) )л') люжст солержать двойные кавычки как смысловой симросс('р, о(р); вол. В фаилах СВУ эта проблема решается удвоением (В(звдвосе СС *р == '"') е1ве росс(' ', а(р); литерачьныл (смысловых) двоиных кавычек; когда счи) тываюшая Сбу-файл программа аназизирует поле с /к двойане кавычке оревраааетсл а одваарвнез */ двойными кавычками, удвоенные двоиные кавычки /* в протвввон случае кавычка орекрааавт чтевве в даевом реквме */ «о(р]; 11( (р+1) 1= " ) ) превращаются в просто лвойныс, но при этом продол(вдоосе = УВЬЗВ; жастся чтение того жс поля р++; /» пропускаем первые кавычка */ (Заметим, что соглашение об удвоенных двойных ) Эта функция принимает массив строк и записывает кавычках отличается от способа помещения двойных их все в одну линию, используя конкрстныи раздели- гу(эр 1= ',' ([ 1вдоосв) кавычек в строку, который используется в С.
В этом тель. Она проводит лвойную проверку отсутствия в стро- *о~э+ Фр языке, конечно, для помещения двойных кавычек в ках выбранного разделителя, поскольку находящиеся в ' ' ) Глава 6 Пересчитренныйязыи С Л речение и имеечение даянии Часть ! данном случае) записывасмая строка содержит запятую, ными буквами. Обычно, однако, имена в йп1-файлах нс Листинг 6.2.
Получение конфигурационной переменной из файла Лпй двойные кавычки или символ новой строки. различают строчные и прописные буквы. Можно снять Фхас1ааа <ятато.ь> В качсствс демонстрации работы этих двух функций чувствительность функции сзчбпгз! к регистру букв, заниже привсдсн фрагмент программы, которая копиру- мснив один или оба вызова я(гпсшр вызовом других ст один СКчг-файл в друтой, выбирая при этом опрсдс- функций, нсчувствитсльных к регистру, таких как Осистая НАХЫНЕ )ООО лснныс колонки.
Массив яс!со)я содержит номера выб- я!Гп!сглр или яцтюязссшр, которые досзупны в качссгвс сваг и раиных колонок; в данном примсрс нужно извлечь приложений во многих системах. гачеагса(соаят сваг иШа, сопят сваг *васс, солят сваг ихау) колонки под нолесрами 1, 3 и 5. Содержащаяся в листинге 6.2 программа дсмонстри( руст основной метод чтения таких файлов. В реальной Р1ЬХ чтр! Ьлс ии1со1и[) = (1, 3, з)! Ьат аяа1со1я = 3! жс ситуации, если возникаст необходимость считать ататхс сваг Иаа[НАХЫПВ).
несколько конфигурационных псрсмснных, предпочтисааг *, егат БОЬЫ сваг *агг1[НАХСОЬ81, 'агг2[НАХСОЬВ); тсльнсс нс открывать файл и нс искать секцию для кажхат 1еа; дой переменной в отдельности. На ччсЬ-сайтс "Диа- и ((гр торса(111а, г )) == ИОЬЬ) ий11а([Чета(11аа. а)яео((Иаа), Ир) ! НОЬЬ) ( Софт" находится расширенная версия функции )п)[с!сй, хатата НОЬЬ; И ([р = ятггсхг(11ае, '1а')) (= НОЬЬ) которая нс предполагает столь частого повторения операции открытия файла и поиска в нсм. аа = сячЬигяс(Иае, агг1, НАХСОЬО); 1еа = всг1еа(васс!.
Усовершенствованные методы И (иИая 1= '[') Пересмотренная язиг С Часть 1 Индексная адресация 1геад(а.вег, 1, 20, ур) ху(в.з == 3> Далее приведена программа лля чтения индексов, прсдшествуюшая поиску отдельных записей. Список индексов начинается с начала файла и заканчивается записью "[евй о( >вг)ех)'1 ( Ранее мы упомянули, что одним из способов повышения эффективности работы с файлами переменного формата является индексация. Нашим последним прирос>пг(п.1, ур)Г па = О; рп111оае(а.у, тр); мором будет текстовый файл данных переменного фор- яь(1е(учета(11пе, агхепу(11ве), 1(р> >= вцьь) уяг>ге(а.птг, 1, 20, 1р); мата, подобный последнему примеру в разделе "Двоич( Ьгеай; ные файлы", но в данном случае содержащий множество 11(вегпепр(11пе, [ОЫ)[епд пу[ОЫ), 7) = О> > записей.
Первая часть файла — легко читаемые инлек- Ьгеав; > пя сы, позволяющие быстро находить полные записи в хй(пв = 21 Поскольку каждая запись сделана с помощью фун- этом файле. Поскольку сдвиг каждой записи относикций рцт)в(, рвтйоа( и Йтнте, прочесть их можно, выз- тельно начала файла неизвестен до тех пор, пока запись вав соответственно функции берл(, йетйоа( и Ггеай. Пе- не будет записана, позднее необходимо возвращаться и рел чтением кюкаой записи вызывается функция йе)1 для вписывать в ннлексы величины сдвигов. аегпсг 1пдвх *гхр ВОЬЬ> записи текущего сдвига в файле.