–  Вместо двух вложенных циклов здесь остался только один — внешний.

–  Вместо считывания во внутреннем цикле в переменную типа Char:

Read(FText, C);

и пропуска символа перевода строки после внутреннего цикла:

ReadLn(FText);

теперь используется одно считывание в переменную типа string, совмещённое с пропуском символа перевода строки:

ReadLn(FText, S);

Из данного примера можно сделать вывод о том, что при решении многих задач построчная обработка текстовых файлов будет заведомо проще в реализации, чем посимвольная. Необходимо, однако, выбирая построчную обработку, учитывать следующее:

–  Тип данных string не является частью стандарта языка Паскаль и доступен лишь в некоторых (хоть и популярных) его реализациях. Поэтому, использование его может привести к меньшей переносимости программ.

–  Программы, использующие построчную обработку, могут использовать для своей работы большее количество оперативной памяти.

–  Максимальное количество символов в строке, хранящейся в переменной типа string, ограничено сверху реализацией (обычно — 255), в то время как в строке текстового файла количество символов не ограничено (точнее, ограничено максимальным размером файла, зависящим от операционной системы, обычно — на много порядков большим). При считывании из файла в строковую переменную:

ReadLn(FText, S);

в переменную S будет прочитано не больше символов, чем она может вместить (например, 10, если она описана как string[10]). Поскольку процедура ReadLn пропускает все непрочитанные символы до конца текущей строки (вместе с символом перевода строки, если он есть), может получиться так, что будет обработана только часть строки из файла. Этот недостаток можно исправить, используя двойной цикл, аналогичный посимвольной обработке (см. далее пример 5). Однако, в этом случае программа потеряет исходную простоту.

НЕ нашли? Не то? Что вы ищете?

Пример 5. Вывести содержимое текстового файла на экран (с сохранением разбиения на строки), используя построчную обработку и учитывая возможность длинных строк в файле.

Входные данные:

SFileName — имя текстового файла;

Текст программы:

{

Вывод на экран содержимого текстового файла,

корректная построчная обработка длинных строк

}

program s_1_3;

var

SFileName, S: string;

FText: Text;

begin

{ Ввод имени файла }

Write('Имя файла: ');

ReadLn(SFileName);

{ Открытие файла на чтение }

Assign(FText, SFileName);

Reset(FText);

{ Вывод содержимого файла }

while not EOF(FText) do { пока не конец файла }

begin

while not EOLn(FText) do { пока не конец строки }

begin

Read(FText, S); { чтение подстроки из файла }

Write(S) { печать подстроки }

end; { while not EOLn(FText) }

ReadLn(FText); { пропуск в файле перевода }

WriteLn { печать перевода строки }

end; { while not EOF(FText) }

{ Закрытие файла }

Close(FText)

end.

Пример 6. Скопировать содержимое одного текстового файла в другой, но без пустых строк.

Входные данные:

SInFileName — имя входного текстового файла;

SOutFileName — имя выходного текстового файла;

Текст программы:

{

Копирование содержимое одного текстового файла

в другой без пустых строк, построчная обработка

}

program s_2_2;

var

SInFileName, SOutFileName, S: string;

FIn, FOut: Text;

begin

{ Ввод имён файлов }

Write('Имя входного файла: ');

ReadLn(SInFileName);

Write('Имя выходного файла: ');

ReadLn(SOutFileName);

{ Открытие файлов на чтение и запись }

Assign(FIn, SInFileName);

Reset(FIn);

Assign(FOut, SOutFileName);

Rewrite(FOut);

{ Копирование содержимого файла }

while not EOF(FIn) do { пока не достигнут конец файла }

begin

ReadLn(FIn, S); { чтение строки, пропуск перевода }

if S <> '' then { если считанная строка не пустая, }

WriteLn(FOut, S) { вывод строки и перевода строки }

end; { while not EOF(FIn) }

{ Закрытие файлов }

Close(FIn);

Close(FOut)

end.

При сравнении данного решения с решением той же самой задачи методом посимвольной обработки (текст программы s_2_1 из примера 2) можно отметить упрощение алгоритма. Действительно, вместо использования логической переменной для проверки строки на пустоту используется более ясное для понимания сравнение: “S <> ''”. Очевидно, что при решении других задач выбор построчной обработки может привести к ещё большему выигрышу в простоте получаемого алгоритма, здесь в полной мере раскрываются все её преимущества.

Пример 7. Скопировать содержимое одного текстового файла в другой, но без n последних строк.

Входные данные:

SInFileName — имя входного текстового файла;

SOutFileName — имя выходного текстового файла;

N — количество строк в конце входного файла, которые не нужно копировать в выходной.

В отличие от предыдущего решения той же задачи (пример 3), далее будет использован алгоритм, требующий одного прохода по входному файлу, вместо двух, с использованием буфера строк. Возможность использования данного алгоритма открывается благодаря применённой построчной обработке файлов.

Алгоритм состоит из двух частей. Сначала происходит заполнение буфера (массив из строк) N первыми строками входного файла. Затем в цикле, перебирающем оставшиеся строки во входном файле, последовательно записывается в выходной файл строка из буфера в позиции I, и затем в ту же самую позицию в буфере считывается из входного файла очередная строка. При этом I меняет своё значение на каждой итерации циклически: от 1 до N, затем снова 1, и так далее. Таким образом, массив из строк выступает в качестве циклического буфера, и чтение/запись на второй стадии алгоритма организованы таким образом, что на одной итерации в выходной файл будет записана строка, считанная N шагов назад (либо в том же самом цикле, либо на первом шаге алгоритма, когда происходило только чтение).

Текст программы:

{

Копирование содержимое одного текстового файла

в другой без n последних строк, построчная

обработка

}

program s_3_2;

const

NMax = 100;

var

ASBuffer: array [1 .. NMax] of string;

SInFileName, SOutFileName: string;

FIn, FOut: Text;

I, N: Integer;

begin

{ Ввод данных }

Write('Имя входного файла: ');

ReadLn(SInFileName);

Write('Имя выходного файла: ');

ReadLn(SOutFileName);

Write('Количество строк для пропуска: ');

ReadLn(N);

if (N < 1) or (N > NMax) then

WriteLn(

'Ошибка: количество пропускаемых строк ',

'должно быть положительным и не больше ',

NMax)

else

begin

{ Открытие входного файла на чтение }

Assign(FIn, SInFileName);

Reset(FIn);

{ 1. Считывание в буфер первых N строк }

I := 0;

while not EOF(FIn) and (I < N) do

begin

{ Определение следующей позиции в буфере }

I := I + 1;

{ Чтение очередной строки в элемент I буфера }

ReadLn(FIn, ASBuffer[I])

end; { while not EOF(FIn) and (I < N) }

{ Открытие выходного файла на запись }

Assign(FOut, SOutFileName);

Rewrite(FOut);

{ 2. Запись строк из буфера в выходной файл }

{ с одновременным считыванием в него строк }

{ из входного файла }

I := 0;

while not EOF(FIn) do

begin

{ Определение следующей позиции в циклическом буфере }

{ I будет меняться на каждой последующей итерации: }

{ 1, 2, ..., N, 1, 2 и т. д. }

I := 1 + I mod N;

{ Запись строки из элемента I буфера, эта строка }

{ была прочитана из входного файла N шагов назад }

WriteLn(FOut, ASBuffer[I]);

{ Чтение очередной строки в элемент I буфера }

ReadLn(FIn, ASBuffer[I])

end; { while not EOF(FIn) }

{ Закрытие файлов }

Close(FIn);

Close(FOut)

end { if N > NMax (else) }

end.

Замечание: Данная программа (как и программа s_3_1 из примера 3) будет считать, что количество строк в файле на единицу больше количества в нём символов перевода строки. Так, будет считаться, что файл с содержимым:

ABC┘

состоит из двух строк (первая строка: “ABC”, вторая строка пустая). Поскольку программа всегда добавляет в конец выходного файла символ перевода строки (если последняя записанная строка не пустая), копирование содержимого файла, в конце которого есть символ перевода строки, без одной последней строки фактически приведёт к тому, что последняя (пустая) строка также будет скопирована.

При сравнении данного решения с решением той же задачи методом посимвольной обработки (текст программы s_3_1 из примера 3) можно отметить, что выбранный здесь способ даёт выигрыш в производительности (необходимо прочитать входной файл всего один раз вместо двух), правда, за счёт существенного увеличения объёма используемой оперативной памяти.

Упражнения

1) Почему в программе s_3_2 из примера 7 запрещён ввод нулевого значения в переменную N? Как изменить программу, чтобы она работала корректно при нулевом значении количества пропускаемых строк?

2) Почему программа s_3_1 будет работать корректно для случая, когда количество пропускаемых строк (N) будет больше общего количества строк во входном файле? В чём отличие, с этой точки зрения, данной программы от программы s_3_1 из примера 3?

3) Как можно исправить программы из примеров 4–7 так, чтобы в конец выходного файла (в конце печати на экран в примере 4) выводился символ перевода строки только в том случае, когда он есть в конце соответствующей строки входного файла?

2.3  Изменение содержимого текстовых файлов

Поскольку текстовый файл невозможно открыть на чтение и запись одновременно, изменение его содержимого обычно осуществляется в два этапа. Сначала исходный файл открывается на чтение, и его содержимое (с нужными изменениями) копируется во временный файл, открытый на запись. Затем исходный файл открывается на запись, а временный — на чтение, и содержимое последнего копируется в исходный. В качестве альтернативы можно отметить изменение содержимого на втором этапе (при обратном копировании), вместо первого.

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5