Лекции (984123), страница 5
Текст из файла (страница 5)
Поскольку параметр с именем файла передается операционной системе через программный интерфейс (систсмный вызов, аналогичный О!>ВП), то в написании имени файла дозволены все допустихлые стандартным ЯГ>еП'ом возможности; гевеСГГ, ' ...1.. (' (1аСа('6!еГ.Схл '); Файл с данными берется из директории, находящейся на 2 уровня выше текущей директории,из которой запущена программа.
Процедура гевеС открывает файл для чтения, не стирая содержащихся в нем данных. Процедура ген!Се устанавливает указанный файл в режим записи (перезаписи), стирая возможно содержащиеся в нехл данные. Если файл пуст, то геъ((гГСе также применим, хотя никаких заметных действий при этом не производится. Вторым параметром процедуры генг!Се также иногда, может быль строка, с именем реального файла ОС, сопоставляемого данной файловой переменной.
Поскольку процедура. геъът!Се открывает файл для записи, стирая содержащиеся в н(м данные., то невозможно напрямую осуществить дозапись данных в существующий файл. 207 Последовательный характер обработки и наличие буферной переменной (буфера файла) предполагают, что файл»л могут ассоциироваться с внеплней (вторичной) памятью и другим периферийным оборудованием.
Ьуферпая переменная является Паскаль-абстракцией буфера внешнего устройства операционной системы. Как и где хранятся компоненты зависит от реализации, мы лилль допускаем, что некоторые из них могут находиться В какОй-тО мОм(.'нт В О(>нОВной памяти и тОлькО кОмпОнента ! 1' Всегда н(.'ПОсредсгВ('ннО доступна (8, 9(, если, конечно, файл не пуст. Для описания файла в Си необходимо объявить переменную предопределенного типа 011 Е*. Созданный компилятором виртуальный файловый дескриптор может быть дина,- .(личесл(и связан с конкретным файлом, потоком или устройством с помощью функций стандартной библиотеки языка Си.
Для этого необходим новый файл, в который сначала надо скопировать содержимое старого файла,, а затем, не прекращая сеанса записи, дописать новые комтек»ненгы. Предикат еоГ принимает значение Сгпе, если из файла прочитана последняя компонента. Если из файла не было произведено ни одной операции чтения, то значение данной функции не определено и ее поведение зависит от реализ»щии. Например, Вог!алк1 Рааса1 7.0 установит еоЕ равным Еа1ве.
Иногда, используется трюк с безопасным на пустом файле фиктивным чтением (геас1(1")), побочным эффектом которого является задание значения еоЕ для у.казанного файла.. геас1 ®; 1Е еоЕЕЕ) СЬеп ът1Се1пЕ'Файл„пустр)1 Часто в этом нет необходимости и значение еоЕ устанавливается автоматически. Поскольку файл, как и массив, можно трактовать как указатель на памяттч в данном случае внсспнк)ю а также вви»гу гого что не!вези дс;нтные файловые ггеременнг»~е имеклт болыпой размер и время доступа, встроенная операция присваивания файлов в Паскале нс 1эеализована. ргосес1пге Есру(айаг П, Е2: 61е оЕ Т)1 1 1'1:»- 1ь»»»! Ьеиш геллт1Се ( Е1); гевеС112)1 Мп1е поС еоЕ(Е2) с1о Ьеиш Е1 : - Е2 рпС 111 ); иеС(Е2) 1 епс1:, епс1; Операция конкатенации двух файлов в языке Паскаль тоже не определена. Пополнение файла новой компонентой (добавление к концу последовательного файла новой компоненты), по существу, является конкатенацией файла и пе!теменной того же типа Т, что и компоненты файла,, и осуществляется с помощью стандартной процедуры рпС®, где имя файла, при этом буферной переменной ЕЕ перед ее выполнением надо присвоить значение присоединяемой к файлу компоненты.
Поэтому при необходимости конкатенации файлов ее несложно реализовать средствами языка Паскаль, последовательно присваивая значения компонент второго файла, буферу первого и выполняя каждый раз процедуру рпС. ргосес1пге ЕсаС(л»аг Е, П, Е2: Ие оЕ Т); 1 1:= Е1 /( Ей ) Ьеиш геът1Се1Е)., гевеСЕЕ1 ); гевеС(Е2); Е' Е1 и»п ли 12»иогуьп быть пусгпы»ии. С гереаС рабогполпь ие будет1 1' туЬ11е поС еоЕ(Е1) с!о Ьеиш Е": П рпС(Е)1 цеС(Е1 ) епс1:, 208 тлсЫ1е поС еоЕ(Е2) с1о Ьеи1п Е : — Е2 рпС(Е); иеС(12) епс1 епс1; Отношение равенства над файлами в языке Паскаль не определено.
При необходимости его также несложно реализовать средствами языка. ГнпсС1оп Еес1(тсаг П, 12: Й1е оЕ Т): Ьоо1еап; тс Еес1 с= 11 = 12 с=> 4ф) =;фЕЕ2) 6 11Я = 12ттт Етог г':= 1 Со Я~1)) ) тсаг гса: Ьоо1еап; Ьеи1п гевеС(П): гевеС(12): геа: - Сгпе; Е' гез — индикатор совпадения,, сравнение фаутгтов идегп, их соответстстутолссие коллпотсепгпьс. равтсьс, и ни осЭин из пах не закон'чи,лс,я,. ) исЫ1е гсса апс1 ИпоС соЕЕЕ1)) ог (поС еоЕЕЕ2))) с1о Ьеи1п гез: — гсз апс1 ЕП -- Е2 ); иеСЕП); цеС(Е2) епс1; 1' Поправка индикатора, если коллгтоненты файлов совпада.ли вплоть до окончания одного из них раньше другого ) Еес1 ь- гез апс1 соЕ(Е1) апс1 еоЕ(Е2) епс1; В этом примере предполагается, что переменные типа Т сравнимы, что заведомо справедлиьо для скалярных и строковых типов Паскаля.
В случае, если для типа Т не определено отнопитпие равенства, необходимо предусмотреть булевскую функцию сравнения. В заключение еще раз заметим, что файлового типа в Си нет. Для работы с файлами в стандартной библиотеке Си имеются определения файловых дескрипторов и функций, доступных через заголовочный файл (зЫло.ст>. Вместо описания файловой переменной в Си необходимо определить переменнуто-дескриптор с1тайла, которая является (недопустимой в Паскале!) ссылкой на файл.
Далсе (с ббльшим динамизмом и гибкостью!) Си позволяет сопоставить этому дескриптору существующий либо вновь созда,ваемый реальный файл, установить режимы доступа (чтение, .запись, .перезапись и др,), задать формат и типизацию (интерпретацию) данных файла. Набор функций работы с файлами в Си гораздо более развит, чем в Паскале. Файлы обычно ассоциируются с устройствами внешней памяти и с устройствами ввода- вывода (МЛ, МД, принтер, терминал), о физической организации которых мы уже неоднократно говорили ~72].
209 5.3 Вектор Сгиагппчесъие массивы, т. е. массивы с фиксированной длиной, удобны многим: их длина, известна, поэтому компилятор в состоянии не только сгенерировать инструкции по выделению памяти (в стеке), но и автоматически рассчитать адреса компонент массива при обращении к ним. В случае такого массива легко проверять выход за его границы, уменьшая тем самым вероятность ошибок. Но фиксированная длина во многих случаях становится недостатком. В приложениях линейной алгебры, например, при решении систем линейных алгебраических уравнений размерность задачи редко бывает заранее известной. Поэтому использование статических массивов в таких задачах приводит одновременно как к серьезным непроизводительным затратам, так и к ограничениям: программа оказывается в состоянии решать задачи не более заданной максимальной размерности.
Превышение размерности задачи всего на единицу по сравнению с максимумом приводит к отказу программы. В этой ситуации оказываются полезными дипагиическпе массивы или векторьс, Эти массивы располагаются в куче, и их размер может быть задан произволыю. В идеале длина такого массива ограничена лишь размером доступной памяти, что, разумеется, намного превышает размер стека, выделяемого програмъле. Поскольку длина ъгассива может быть легко изълеггсна, то непроизводитс.гьные издержки отсутствуют.
Недостатком таких массивов является ~возможно) большее среднее время доступа к элементу. Это связано с иерархичностью памяти современных ЭВМ, поддерживакнцих трех- или четырсхуровнсвун> систему основной памяти. Так, мало- или редкоиспользусмые данные, размещенные в виртуальной пагияти, сбрасываются в виар-раздел диска. При необходимости эти данные подгружаются в основную память ЭВМ. Но повременные пропессоры никогда не работают напряъгукь с данными в ОП. Все операнды должны находиться в регистрах, куда они попадают через кэш-память, которая может иметь 2 и более уровней. Главным источнглкоъг критики векторов является обязанность программиста вручную распределять память, что, по мнению многих, в т. ч. и Н. Вирта, служит гарантированным источнглком ошибок.