Решение практических задач на Паскале. Выпуск 4


Чтение информации из файла. ВАРИАНТ 3

Представляю обещанный в прошлый раз http://www.borlpasc.narod.ru/Boris/solve003.htm третий способ хранения данных для программы во внешнем файле. Как отмечалось, его удобно использовать тогда, когда данных много и и их можно объединить в смысловые группы.

Пример входного файла, который я назвал Solv004.ini,  приведен ниже:

#   Файл исходных данных для простой программы,
#  которая вычисляет табличку функции Sin(x) и записывает
#  в файл, демонстрируя третий способ организации
#  входных данных

# Входные данные для расчетов описываются в порядке:
# левая граница, правая и шаг, с которым необходимо выполнить
# вычисления.
# Разделитель целой и дробной части - ТОЧКА
       0.25 см,  34.5 см,   4 см

#  Имя файла, в который необходимо выводить результаты вычисления
#  НЕЛЬЗЯ использовать специальные символы. Желательно не указывать
#  путь к файлу. Тогда он будет создан в той папке, из которой
#  будет запущена программа
       Solv004.out

Как видите, символ "#" служит индикатором того, что это строка - комментарий, и при анализе содержимого файла будет пропущена. Это позволяет писать в ней все, что нужно, не стесняясь в выражениях и не задумываясь о том, сколько места этот комментарий занимает :))

За основу анализирующей программы я взял тот же вариант, что был описан в предыдущем случае. Только переписал процедуру ReadData. По-прежнему она использует процедуру FindReal, описанную в модуле MyIO003.pas.

Внимание:

Тестирование показало, что в процедуре FindReal нужно изменить строчку:

if NBeg = len then EXIT;     {     Все, дошли до конца строки, а цифр не нашли.
                                    Выходим и код ошибки уже установлен }

Знак "=" ( равно) нужно заменить на ">" (больше). Иначе, если последний символ - одна цифра, то он пропускается!

if NBeg > len then EXIT;

Я приведу текст только процедуры чтения данных. В ней предполагается, что данные, как и раньше, записаны в определенном порядке. Строки, начинающиеся с символа "#" не анализируются.

В процедуре ReadData нужно проанализировать несколько строк. Поэтому добавлена переменная, в которой храним номер анализируемой строки. Для анализа строки с нужным номером используется оператор Case. Выделены операторы Continue и Break, которые используются для упрощения кода. К сожалению, "некоторые" вместо них используют метки. А это не есть хорошо!

function ReadData(AFileName: String;
  var Left, Right, Step: Real;
  var AName: String): Boolean;
var
  ini: Text;
  buf: String;
  nString: Integer; {Нужно, чтобы определить, какая это строка
                     с параметрами:
                     первая значащая - в ней границы,
                     вторая - в ней имя файла}
  k, opCode: Integer;

  {Вспомогательная функция, облегчающая работу.
   Возвращает значение ИСТИНА, если это строка - комментарий
   (первый символ - "#" ) или пустая}
  function IsComment(str: String): Boolean;
  begin
    IsComment:=True;
    {Пропустим первые симовлы - пробелы}
    while (str[1]=' ') and (length(str)>1) do delete(str, 1, 1);
    if str = '' then Exit;  {пустая - точно нет данных}
    IsComment := str[1] = '#'
  end;

begin
  ReadData:=False;  Assign(ini, AFileName); {$I-} Reset(ini); {$I+}
  if IOResult <> 0 then begin
    WriteLn('Не могу открыть файл с исходными данными:');
    WriteLn(AFileName);   Exit;
  end;
  ReadData := TRUE;
  Left := 0;  Right:= 1; Step := 0.1;
  AName:= 'out004.dat';   	{Значение по умолчанию}
    
  nString:=1;
  while NOT EOF(ini) do begin
    ReadLn(ini, buf);
    if IsComment(buf) then Continue;
    {Эта часть будет пропущена, если buf опознана как комментарий}
    k:=1;
    Case nString of
      1: begin
           inc(nString);
           FindReal(buf, Left,  k, opCode);       if OpCode <> 0 then Break;
           FindReal(buf, Right, k, opCode);      if OpCode <> 0 then Break;
           FindReal(buf, Step,  k, opCode);      if OpCode <> 0 then Break;
         end;
      2: begin {Нужно только удалить возможные пробелы.
                Мы пишет программу под ДОС - там длинные имена не
                разрешены}
             inc(nString); {чтоб больше не анализировалось ничего}
             while pos(' ', buf) <> 0 do delete(buf, pos(' ',buf), 1);
             if buf <> '' then AName:=buf
         end;
    end;
  end;
  Close(ini);
end;

Да, еще я изменил код "вычисляющего" цикла в теле программы так, чтобы значение, соответствующее "правой" границе вычислялось даже тогда, когда начальное значение и шаг таковы, что в правую (большую) границу "не попадаем". Все исходные файлы можно скачать в виде архива по адресу http://www.borlpasc.narod.ru/Boris/solv004.zip.

Свои вопросы и предложения присылайте Борису

Мы приглашаем Вас и Ваших друзей к сотрудничеству. Напишите, какая проблема Вас лично интересует - и мы постараемся помочь Вам. Поделитесь со всеми, если Вам удастся найти красивое решение. Присылайте свои программы, и если они хороши, то опубликуем их с обязательным указанием Вашего авторства.

По всем вопросам можно писать либо в Гостевую книгу нашего сайта на www.turbopascal.tk, либо мне, автору этого выпуска, © Сурину Борису: surin_bp@mail.ru, ICQ: 320096696. Постараюсь ответить на все вопросы и учесть все разумные предложения

Рассылка поддерживается сайтом www.turbopascal.tk. При перепечатке ссылка на сайт обязательна

Внимание: сессия и экзамены еще не начались - самое время подписаться на нашу рассылку:
Рассылки@Mail.ru
Шпаргалки

Hosted by uCoz