11. Текстови файлове. Процедури и функции в Borland Pascal за работа с текстови файлове. Изтриване и преименуване на файлове от програма на Borland Pascal.
 
Дефиниция 11.1

Текстов файлов, наречен още ASCI файл, се състои само от символи от азбуката на компютъра, разпределени по редове. В тях няма други управляващи символи освен символите за нов ред, начало на ред и табулация (виж точка 8).

Такива файлове са много удобни за съхраняване на големи обеми от данни, защото могат да се четат и да се редактират от всякакви текстови редактори, като Edit, Pe2 за MS DOS, Notepad, WordPad, Write, Word за Windows и др. Много програмни системи генерират или четат данни от текстови файлове (напр. MS Excel, Statgraph, Statistica, Mathematica и др.). Следователно данни, въведени и редактирани от удобни за работа текстови редактори или генерирани от различни програмни системи, ако са съхранени в текстови файлове, могат да се прочетат и обработят от програма на езика Pascal и обратно, изходни данни на програма на Pascal, ако са във текстов файл, могат да се прочетат, редактират, форматират и включат в някакви по-големи документи от повечето текстообработващи системи или могат да се заредят и допълнително обработят от най-различни програмни системи.

Друго предимство на текстовите файлове е, че те могат да съдържат разнотипна информация в текстов вид.

За текстови файлове в Pascal има специален тип text. За да се работи с такъв файл трябва да се дефинира файлова променлива от тип text

    име: text;

Подобно на файловете с еднотипни елементи от предната глава за текстовия файл първо трябва да се осъществи връзка между името на файла и файловата променлива и след това той трябва да се отвори. Накрая, след като завърши работата с файла, той трябва да се затвори. Връзката между името на файла и файловата променлива става с библиотечната процедура

    procedure assign(f: text; s:string);

където f е файловата променлива, а в низа s е името на файла върху външния носител (виж точка 10).

Отварянето на файла става по три различни начина според това, какво ще се прави с него.

Създаване на нов файл става с библиотечната процедура

    procedure rewrite(f: text);

където f е файловата променлива. Създава се нов празен файл с указаното в assign име на външния носител. Ако вече съществува файл с това име, той се унищожава. В така отворения файл може само да се пише.

Отваряне на съществуващ файл само за четене става с библиотечната процедура

    procedure reset(f: text);

където f е файловата променлива. Файлът с указаното в assign име се отваря, четящата глава се позиционира върху първия символ от файла. От така отворения файл може само да се чете.

Отваряне на съществуващ файл за добавяне на текст към края на файла става с библиотечната процедура

    procedure append(f: text);

където f е файловата променлива. Файлът с указаното в assign име се отваря, четящата глава се позиционира след последния символ. Към края на така отворения файл може само да се записва допълнителен текст. От тук става ясно, че при текстови файлове нямаме пряк достъп и че не може да се промени съдържанието от вътрешността на вече съществуващ текстов файл, а най-много само да се добави текст към неговия край.

Пример 11.1:

    var
        f1, f2, f2: text;

    begin

        assign(f1, 'c:\newfile.txt');
        rewrite(f1);     { Създава нов текстов файл в главната директория на диск c: }
        assign(f2, 'readlile.txt');
        reset(f2);        { Отваря файл от директорията на програмата само за четене}
        assign(f3, 'a:appfile.txt');
        append(f3);    {Отваря файл от дискета за добавяне на данни към края му }
        .............

    end
.

Писането в текстов файл става по начин аналогичен с този при писане върху екрана (виж точка 2) с библиотечните процедури

    write(f, израз1, израз2, .., изразN)
    writeln(f, израз1, израз2, .., изразN)

където f е файловата променлива, а стойностите на израз1, израз2, .., изразN се записват във файла като текст. Разликата между двете процедури е, че след записване на стойността на изразN при write пишещата глава остава на същия ред и чака следващо записване във файла, а при writeln тя създава нов ред и чака да пише на него. Може да се напише само

    writeln(f)

тогава само се създава нов ред във файла. Към изразите, чието стойности се записват във файла може да има форматиращи команди, указващи в колко позиции ще се запише стойността. Ако израза е от тип integer, то форматираща команда има вида

    израз:брой_позиции

Ако числото не се побира в брой_позиции, те се допълват, ако ли пък е с по-малко разряди от брой_позиции, то се допълва с интервали отляво.

Ако израза е от тип real, то форматираща команда има вида

    израз:брой_позиции:точност

където точност задава брой числа след десетичната точка и точност < брой_позиции - 2..

Ако израза е от тип string или char то форматираща команда има вида

    израз:брой_позиции

Ако низът е по-дълъг от брой_позиции, той се отрязва, ако ли пък е по-къс, той се допълва с интервали отдясно. брой_позиции и точност са изрази със стойности цели положителни числа.

Ако няма форматиращи команди или интервали между записваните стойности, те ще се залепят една за друга.

Четене от текстов файл става чрез библиотечните процедури

    read(f, променлива1, променлива2, ..., променливаN)
    readln(f, променлива1, променлива2, ..., променливаN)

където f e фазовата променлива, а в променлива1, променлива2, ..., променливаN ще се заредят стойностите прочетени от файла. Четенето започва от символа сочен от четящата глава. Отделните стойности в текста трябва да са разделени една от друга с интервал, табулация или нов ред. Стойностите, ако е възможно, се преобразуват от текстов вид към типа на съответните променливи, в които те се зареждат. Ако има несъответствие между типа на данната в текста, от който се чете и типа променливата, в която тази данна трябва да се зареди, възниква входно-изходна грешка. Т.е главата трябва да сочи правилно изписано цяло число за да може то да се прочете и зареди в променлива от тип integer или real. Разликата между read и readln е, че след завършване четенето от файла с read четящата глава остава на същия ред, а след завършване на readln главата преминава на нов ред. Възможно е да се зададе само

    readln(f)

и тогава главата ще премине на нов ред в файла.

Възниква въпроса, ако се чете информация от един ред от текста с read, как да се разбере, че главата е стигнала края на реда за да се премине на нов ред с readln. За тази цел трябва да се ползва библиотечната функция

    function eoln(f: text): boolean;

Тази функция дава true, ако четящата глава е достигнала края на ред и false, ако сочи символ вътре в реда.

Проверката, дали четящата глава е стигнала края на файла, става с библиотечната функция

    function eof(f: text): boolean;

Тази функция дава true, ако четящата глава е достигнала края на файла и false, ако сочи символ вътре във файла. .

Накрая след завързване работата с даден файл той се затваря. Това става с библиотечната процедура

    procedure close(f: text);

При работа с текстови файлове могат да възникнат редица грешки по време на изпълнение на програмата (run time error). Обикновено това ще предизвика прекъсване на програмата. Как да предпазим програмата от такова прекъсване бе показано в точка 10 - чрез инструкция към компилатора {$I-}, не позволяваща прекъсване на програмата при входно-изходна грешка и чрез функцията ioresult, проверяваща за входно изходни грешки.

Задача 11.1: Във текстов файл има записани няколко реда и колони реални числа, например

3 5.4 -7 0

-2.1 4 0.5 7

1 -0.3 3 4.3

Да се състави програма, която да прочете тези числа в двумерен масив и да намери средните аритметични от колоните в масива. Резултатите да се добавят към края на файла.

Анализ: Първо, ще отворим файла за четене, ще прочетем числата в масива, като през това време ще преброим редовете и колоните. След това в друг едномерен масив ще намерим средните аритметични. Накрая ще отворим файла за добавяне и ще добавим тези средно аритметични.

Програма

program textfile;
    uses WinCrt;

    const
max = 20;

    var

        f: text;
        a: array[1 .. max, 1 .. max] of real;
        b: array[1 .. max] of real;
        n, m, i, j: integer;
        name: string[50];

    begin

        write('Въведете името на файла:');
        readl(name);
        assign(f, name);     { Връзка между файловата променлива и името на файла }
        reset(f);                 { Отваряне на файла за четене }
        n := 0;

        while not
eof(f) do begin         { Цикъл до достигане края на файла }

            m := 0;
            n := n + 1;

            if
n > max then exit;             { Прекъсване на цикъла }
            while not
eoln(f) do begin   { Цикъл до достигане края на ред }

                m := m + 1;

                if
m > max then exit;

                    read(f, a[n, m])             { Четене на поредно число от файла }

            end
;

            readln(f)                               { Предвижване четящата глава на нов ред }

        end
;

        close(f);                                   { Затваряне на файла }

        if
(n > max) or (m > max) or (n = 0) or (m = 0)
            then
writeln('Твърде много редове или стълбове или грешна структура на файла !')

            else begin

                for
i := 1 to n do begin

                    b[i] := 0;

                    for
j := 1 to m do

                        b[i] := b[i] + a[i, j];
                    b[i] := b[i] / n

                end
;

                append(f);                     { Отваряне на файла за добавяне към края му }
                writeln(f);                      { Нов ред във файла }

                for
i := 1 to m do

                    write(f, a[i, j]:8:2);     { Записване на число във файла }
                close(f);                        { Затваряне на файла }

            end

    end
.

Понякога възниква необходимостта от програма да се преименува или изтрие файл. За тази цел в Borland Pascal има две процедури. Процедурата за преименуване е

    procedure rename(файлова_променлива; s: string);

където низът s задава новото име на файла. Старото име трябва преди това да е свързано с файловата променлива чрез assign.

Процедурата за изтриване на файл е

    procedure erase(файлова_променлива);

Файлът, чието име преди това е било свързано чрез assign към файловата променлива, се изтрива.

Задача 11.2: Да се състави програма, която от файл с реални числа премахва зададено число.

Анализ: Ще копираме във временен файл всички числа от файла, различни от зададеното число. След това ще изтрием файла и временният файл ще преименуваме с името на изтрития файл.

Програма

program delfromfile;
    uses WinCrt;

    var

        f, f1: file of real;
        a, b: real;
        find: boolean;
        name: string[50];

    begin

        write('Въведете името на файла:');
        readl(name);
        write('Задайте число за премахване от файла:');
        readln(b);
        assign(f, name);             { Връзка между файловата променлива и името на файла }
        reset(f);                         { Отваряне на файла за четене }
        assign(f1, 'temp.dat');
        rewrite(f1);                    { Отваряне на нов временен файл }
        find := false;

        while not
eof(f) do begin

            read(f, a);                  { Четене на число от файла }

            if
a = b
                then
find := true
                else
write(f2, a)    { Записване на различното от b число във временния файл}
        end
;

        close(f);
        close(f1);

        if
find
            then begin
                 { Във файла са открити числа равни на b }

                erase(f);                  { Изтриваме файла }
                rename(f1, name)    { Преименуване на временния файл с името на изтрития }

            end
            else begin

                writeln('Няма такова число във файла !');
                erase(f2)                { Изтриваме временния файл }

            end

    end
.


Съдържание


10. Файлове в Pascal. Файлове от определен тип. Достъп до данните във файла. Процедури и функции в Borland Pascal за работа с файлове от определен тип.