Помощь - Поиск - Пользователи - Календарь
Полная версия: работа с файлами
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
IchLiebeDich
Помогите пожалуйста! Как исправить ошибку? Не могу понять, как её исправить, подскажите, очень-очень надо!.. Программа по работе с данными из таблицы. Данные хранятся в текстовом файле(прикреплён к сообщению, см ниже).
Код
program TABLIZA;
uses crt;
const
   p_menu:array [1..7] of string=('-Чтение данных из файла   ',
                                  '-Просмотр входной таблицы',
                                  '-Добавление записей',
                                  '-Удаление записей        ',
                                  '-Обработка и просмотр данных',
                                  '-Сохранение данных в файл',
                                  '-Выход                    ');

type
vhod_t=record                     {входная таблица}
   number:byte;
   FIOdir:string[15];
   FIOen:string[15];
   plan:real;
   fact:real;
end;

vyhod_t=record                     {выходная таблица}
   number:integer;
   FIOdir:string[15];
   FIOen:string[15];
   plan:real;
   fact:real;
   otklon:real;
end;



ukaz=^spisok;                      {список}
spisok=record
  inf:vhod_t;
  next:ukaz;
  end;

  ukaz1=^spisok1;
  spisok1=record
  inf:vyhod_t;
  next:ukaz1;
  end;


var
file_in:file of vhod_t;         {входной и выходной файлы}
file_out:file of vyhod_t;
NewL,nach,kon,vremen:ukaz;
NewE,nach1:ukaz1;
nomermenu, year:integer;
vh_name, vyh_name:string[20];
vh_t:vhod_t;
vyh_t,vyh_t1:vyhod_t;

procedure MENU(var nomermenu:integer);
var x,y,i:integer;
c:char;
begin
x:=28;
y:=1;
gotoXY(x,8);
textcolor(13);
writeln('   Выберите пункт меню:   ');
textcolor(3);
for i:=1 to 7 do begin
gotoXY(x,i+8);
writeln(p_menu[i]);
end;
textcolor(4);
gotoXY(x,y+8);
writeln(p_menu[y]);
while true do
begin
c:=readkey;
case ord(c) of
   80:if y<7 then y:=y+1;
   72:if y>1 then y:=y-1;
   13:break;
end;
gotoXY(x,8);
textcolor(13);
writeln('   Выберите пункт меню:   ');
textcolor(3);
for i:=1 to 7 do begin
gotoXY(x,i+8);
writeln(p_menu[i]);
end;
textcolor(4);
gotoXY(x,y+8);
writeln(p_menu[y]);
end;
nomermenu:=y;
textcolor(white);
end;

procedure readfile(vh_name:string);
    begin
writeln('Введите путь к входному файлу');
readln(vh_name);

assign(file_in,vh_name);
reset(file_in);
if IOResult>0 then begin
writeln('Ошибка открытия файла');
exit;
end;
read(file_in,vh_t);    {=================ЗДЕСЬ ВЫДАЁТСЯ ОШИБКА===============}
New(NewL);
NewL^.inf.number:=vh_t.number;
NewL^.inf.FIOdir:=vh_t.FIOdir;
NewL^.inf.FIOen:=vh_t.FIOen;
NewL^.inf.plan:=vh_t.plan;
NewL^.inf.fact:=vh_t.fact;
NewL^.next:=nil;
nach:=NewL;
kon:=NewL;
reset(file_in); read(file_in,vh_t);
while not EOF(file_in) do begin
read(file_in,vh_t);
New(NewL);
NewL^.inf.number:=vh_t.number;
NewL^.inf.FIOdir:=vh_t.FIOdir;
NewL^.inf.FIOen:=vh_t.FIOen;
NewL^.inf.plan:=vh_t.plan;
NewL^.inf.fact:=vh_t.fact;
NewL^.next:=nil;
kon^.next:=NewL;
kon:=NewL;
end;
end;

procedure prosmotr_vhod(nach:ukaz);
var x,y,i,n,t:integer;
c:char;
begin
writeln('Просмотр таблицы':70);
x:=1;y:=1;
{gotoxy(x,y);}
writeln('|--------|---------------|---------------|--------------|-----------|');
writeln('| Номер  | ФИО директора |  ФИО главного | израсходовано| фактически|');
writeln('|        |               |  энергетика   |   тыс КВт*ч  | тыс КВт*ч |');
n:=0;
vremen:=nach;
  while vremen<>nil do
begin

writeln('|--------|---------------|---------------|--------------|-----------|');
writeln('|',vremen^.inf.number:6,'|',vremen^.inf.FIOdir:15,'|',vremen^.inf.FIOen:15,'|',vremen^.inf.plan:4,'|',
vremen^.inf.fact:4,'|');
vremen:=vremen^.next;
n:=n+1;
end;
writeln('|--------|---------------|---------------|--------------|-----------|');

while true do begin
c:=readkey;
t:=ord(c);
if t= 13 then break;

if t=8 then begin Delline;   delline;end;
if t=  72 then begin
                    if y>1 then y:=y-2;
                    gotoxy(x,y);
                    if (y=1) then
                      vremen:=nach^.next;
                        while vremen<>nil do
begin

writeln('|--------|----------------|---------------|--------------|----------|');
writeln('|',vremen^.inf.number:6,'|',vremen^.inf.FIOdir:15,'|',vremen^.inf.FIOen:15,'|',vremen^.inf.plan:4,'|',
vremen^.inf.fact:4,'|');
vremen:=vremen^.next;
n:=n+1;
end;

                end;
if t=80 then begin
                      if y<n then y:=y+2;
                      gotoxy(x,y);


              end;


end;


end;

procedure dobavlenie( var kon:ukaz;var nach:ukaz);
begin
writeln('Введите номер завода');
readln(vh_t.number);
writeln('Введите ФИО директора');
readln(vh_t.FIOdir);
writeln('Введите ФИО главного энергетика');
readln(vh_t.FIOen);
writeln('Израсходовано энергии по плану');
readln(vh_t.plan);
writeln('Израсходовано энергии фактически');
readln(vh_t.fact);
New(NewL);
NewL^.inf.number:=vh_t.number;
NewL^.inf.FIOdir:=vh_t.FIOdir;
NewL^.inf.FIOen:=vh_t.FIOen;
NewL^.inf.plan:=vh_t.plan;
NewL^.inf.fact:=vh_t.fact;
NewL^.next:=nil;
if kon=nil then
nach:=NewL
else
kon^.next:=NewL;
kon:=NewL;
write(file_in,vh_t);
end;

procedure udalenie;         {удаление из начала списка}
var
temp:ukaz;
begin
if nach<>nil then
begin
temp:=nach;
nach:=nach^.next;
dispose(temp);
if nach=nil then
kon:=nil;
end;
end;

procedure obrabotka_prosmotr;
var sump,sumf,sumo:real;
sred:real;
kon:ukaz1;
begin
sump:=0;
sumf:=0;
sumo:=0;
nach1:=nil;
kon:=nil;
seek(file_in,0);
writeln('Отклонение факта от плана (со знаком)');
writeln('|--------|---------------|---------------|--------------|-----------|-----------|');
writeln('| Номер  | ФИО директора |  ФИО главного | израсходовано| фактически| отклонение|');
writeln('|        |               |  энергетика   |   тыс КВт*ч  | тыс КВт*ч | тыс КВт*ч |');

read(file_in,vh_t);
New(NewE);
NewE^.inf.number:=vh_t.number;
vyh_t1.number:=NewE^.inf.number;
NewE^.inf.FIOdir:=vh_t.FIOdir;
vyh_t1.FIOdir:=NewE^.inf.FIOdir;
NewE^.inf.FIOen:=vh_t.FIOen;
vyh_t1.FIOen:=NewE^.inf.FIOen;
NewE^.inf.plan:=vh_t.plan;
vyh_t1.plan:=NewE^.inf.plan;
NewE^.inf.fact:=vh_t.fact;
vyh_t1.fact:=NewE^.inf.fact;
writeln('|--------|---------------|---------------|--------------|-----------|-----------|');
writeln('|',NewE^.inf.number:6,'|',NewE^.inf.FIOdir:15,'|',NewE^.inf.FIOen:15,'|',
NewE^.inf.plan:4,'|',NewE^.inf.fact:4,'|',NewE^.inf.otklon:5,'|');



while not EOF(file_in) do  begin
read(file_in,vh_t);
if((vh_t.plan>0)and(vh_t.fact>0)) then begin
New(NewE);
NewE^.inf.number:=vh_t.number;
vyh_t1.number:=NewE^.inf.number;
NewE^.inf.FIOdir:=vh_t.FIOdir;
vyh_t1.FIOdir:=NewE^.inf.FIOdir;
NewE^.inf.FIOen:=vh_t.FIOen;
vyh_t1.FIOen:=NewE^.inf.FIOen;
NewE^.inf.plan:=vh_t.plan;
vyh_t1.plan:=NewE^.inf.plan;
NewE^.inf.fact:=vh_t.fact;
vyh_t1.fact:=NewE^.inf.fact;
writeln('|--------|---------------|---------------|--------------|-----------|-----------|');
writeln('|',NewE^.inf.number:6,'|',NewE^.inf.FIOdir:15,'|',NewE^.inf.FIOen:15,'|',
NewE^.inf.plan:4,'|',NewE^.inf.fact:4,'|',NewE^.inf.otklon:5,'|');

kon:=NewE;
NewE^.next:=nil;

while kon<>nil do begin
kon^.inf.otklon:=kon^.inf.plan-kon^.inf.fact;
kon:=kon^.next;
sump:=sump+kon^.inf.plan;
sumf:=sumf+kon^.inf.fact;
sumo:=sumo+kon^.inf.otklon
end;

writeln('|--------|---------------|---------------|--------------|-----------|-----------|');
writeln('|',NewE^.inf.number:6,'|',NewE^.inf.FIOdir:15,'|',NewE^.inf.FIOen:15,'|',
NewE^.inf.plan:4,'|',NewE^.inf.fact:4,'|',NewE^.inf.otklon:5,'|');
end;
end;
writeln('|--------|---------------|---------------|--------------|-----------|-----------|');
if (sump<=0) or (sumf<=0) then  begin writeln('введены неверные значения');readln;exit;

writeln('|        |               |               |',sump:4:2,'|',sumf:5:2,'|',sumo:5:2,'|');
writeln('|--------|---------------|---------------|--------------|-----------|-----------|');
end;
readln;
end;

procedure save_file(var vyh_t1,vyh_t:vyhod_t);
begin
assign(file_out,'d:\vyhodtable.txt');
  rewrite (file_out);
write(file_out,vyh_t1);
write(file_out,vyh_t);
end;

begin
nach:=nil;
kon:=nil;
while true do begin
clrscr;
menu(nomermenu);
case nomermenu of
1:begin clrscr;readfile(vh_name); end;
2: begin clrscr; prosmotr_vhod(nach);  end;
3: begin clrscr; dobavlenie(kon,nach);end;
4:begin clrscr;udalenie;end;
5:begin clrscr;obrabotka_prosmotr;end;
6:begin clrscr;save_file(vyh_t1,vyh_t);end;
7:break;
end;
end;
end.

Нажмите для просмотра прикрепленного файла
Нажмите для просмотра прикрепленного файла
IchLiebeDich
Чуствую, ответа мне не дождаться...
Lapp
Зайди попозже, завтра..
обещаю посмотреть smile.gif
немного пугает взгляд.. smile.gif
извини, размер тоже иногда важен, сама понимаешь... smile.gif
volvo
Цитата
Как исправить ошибку?
Ты же описываешь входной файл, как file of vhod_t, а читать пытаешься из текстового... То, что там содержится вся нужная информафия еще ничего не значит... Формат не тот...

Вот смотри: размер структуры vhod_t = 43 байта, размер файла = 926 байт, 926 на 43 НАЦЕЛО не делится, а ведь
read(file_in,vh_t);
будет пытаться читать данные блоками по 43 байта из файла целое число раз, при нехватке данных программа просто вылетит и все smile.gif

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

Кстати, у тебя есть 2 неточности (которые могут быть проблематичны, если не сейчас, то потом):

1) byte хранит значения 0 - 255, а у тебя в файле присутствуют бОльшие значения...
2) при записи вещественных чисел используется не запятая, а точка...
IchLiebeDich
Цитата
при старте программы (или где нибудь в меню сделать соответствующий пункт) вызывать процедуру корректировки, которая будет читать данные из текстового файла и записывать в типизированный...

а как это сделать? blink.gif
Ozzя
Цитата(IchLiebeDich @ 2.12.2006 6:53) *

а как это сделать? blink.gif

Определить текстовый файл:
var
file_in_text:text;
Читать из него построчно:
Realdn(file_in_text,s);
Разбить полученную строку на части ф-цией GetWords
присвоить полям записи - полученные ф-цией значения
Lapp
Цитата(IchLiebeDich @ 2.12.2006 6:53) *

а как это сделать? blink.gif

Думаю, volvo на этот раз пошутил.. smile.gif. Нет смысла делать такую процедуру и писать на диск дополнительный файл (для которого, при нормальных рабочих размерах нормальной рабочей базы может и не хватить места smile.gif). И к тому же та процедура все равно будет делать именно то, что тебе надо в основном коде - так почему бы не вставить этот код прямо туда?.. При желании можно иметь возможность записывать (и читать) два типа файлов: текстовой и типизированный. Преимуществ одного перед другим я не вижу, кроме возможности редактировать текст в другом обычном редакторе (типа Ноутпада). При записи чисел типизированный файл как правило выигрывает по размеру (не всегда), но если основное содержание текстовое (как тут), то будет скорее наоброт.. Так что я просто рекомендую тебе полностью переключиться на текст (если это разрешается условиями задачи).

если ты со всем этим согласна, читай дальше - описываю, как это сделать.
volvo прав, кое-что придется немного подкорректировать. Во-первых, какой смысл иметь разный формат на вход и выход?? Непременно возникнут противоречия при чтении файлов, созданных одной и той же программой. У тебя же не конвертер, скажем, из jpeg в mp3 (типа шутка smile.gif). Короче,

1. Выбери либо тип vhod_t, либо vyhod_t, а другой тип убери совсем (то есть заменить на выбранный тип). Я думаю, это должен быть vhod_t, так как нет смысла хранить в файле отклонение - его же можно легко посчитать!

Но в типе vhod_t, как уже заметил volvo, поле number описано как byte, чего явно недостаточно при тех номерах, что фигурируют в файле. Вывод:

2. Поле number сделать integer'ом (если и этого недостаточно, то есть бывают номера больше примерно 32000, то LongInt).

Далее, как тоже говорил volvo, в программировании принята американская нотация дейсьвительных чисел, то есть вместо запятой используется точка. Значит нужно:

3. Пройтись по всему файлу данных автозаменой: "," -> ".". Это можно сделать в любом редакторе, типа в Ноутпаде..

Идем дальше. Размещение двух фамилий в одной строке означает, что надо разделять входную информацию на слова. Это некое дополнительное действие, но дело не в том, что нам лень. Дело в том, что такая ситуация может сбить программу с толку, если кому-то вместо просто фамилии захочется ввести имя-отчество или фамилию с именем - тогда пробел между именем и фамилией будет истолкован неверно. Тогда либо нужно запретить ввод в поле фамилии нескольких слов (и следить за этим), либо ввести для разделения фамилий специальный символ и соответствующим образом делить входную строку на две. Я предлагаю поступить по второму методу, и при этом в качестве признака конца фамилии использовать конец строки smile.gif. Это дает явные преимущества: а. файл легче читается; б. для ввода можно использовать процедуру ReadLn. Таким образом:

4. Размести в файле каждую фамилию на отдельной строке.

Теперь касательно самого чтения. Здесь вообще каша.. Зачем ты читаешь сначала в переменную vh_t, а потом перекладываешь в список, да еще по полям?? Мало того, что можно просто переложить в одной строчке так:
NewL^.inf:=vh_t;
- но еще можно и сразу читать в переменную NewL^.inf ! И более того, ты забываешь про существование оператора with, который явно упрощает картину..
Допустим теперь, что ты согласна со мной и читаешь сразу в нужную переменную. Тогда это будет выглядеть так:

5. Оператор
with NewL^.inf do begin
ReadLn(number);
ReadLn(FIOdir);
ReadLn(FIOen);
ReadLn(plan,fact)
end;


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

6. Убрать строку
reset(file_in); read(file_in,vh_t);

Ну и последнее (пока smile.gif). Поскольку мы теперь считаем файл текстовым, то

7. Заменить описания файлов на:
  file_in:text;
file_out:text;


Увы, это не самое последнее... Дальше нужно заменить оператор записи на аналогичную (как в п.5) последовательность (но с заменой Write на Read, а также вставь пробел между plan и fact:

8. Вот так:
with NewL^.inf do begin
WriteLn(number);
WriteLn(FIOdir);
WriteLn(FIOen);
WriteLn(plan,' ',fact)
end;


Дальше я не понял - зачем ты читаешь файл повторно в процедуре obrabotka_prosmotr? Странно это выглядит.. Короче, это надо либо просто убрать, либо заменить чтение по описанной выше схеме..

Уфф.. Нет, размер явно имеет значение... smile.gif Мне кажется, тебе достаточно для первого раза..
IchLiebeDich
спасибо, сейчас попробую чё-нить сделать! smile.gif
Вот у меня тоько один вопрос, а как расчитать значения для поля отклонение? ведь файл текстовый.
Ozzя
Цитата(IchLiebeDich @ 2.12.2006 10:43) *

спасибо, сейчас попробую чё-нить сделать! smile.gif
Вот у меня тоько один вопрос, а как расчитать значения для поля отклонение? ведь файл текстовый.

val
IchLiebeDich
Цитата(Ozzя @ 2.12.2006 9:31) *

val

blink.gif Эт чё значит?
Archon
Цитата
Вот у меня тоько один вопрос, а как расчитать значения для поля отклонение? ведь файл текстовый.
А что за отклонение? Наверное, также, как и раньше. Ведь в текстовом файле можно хранить не только строки, но и числа.
IchLiebeDich
Цитата(Archon @ 3.12.2006 14:38) *

А что за отклонение?

отклонение - имя поля, куда записываются разности значений полей plan и fact.

В текстовом файле хранятся литеры... dry.gif
Archon
Не понимаю, в чём проблема? Считываешь plan и fact и считаешь разность.
IchLiebeDich
Цитата(Archon @ 3.12.2006 15:05) *

Не понимаю, в чём проблема? Считываешь plan и fact и считаешь разность.


в том-то и проблема, что оно не считывается...
Lapp
Цитата(IchLiebeDich @ 10.12.2006 13:35) *

в том-то и проблема, что оно не считывается...

Давай-ка поподробнее.. Покажи свой текущий вариант программы, покажи файл данных.. Скажи, какая именно ошибка возникает.
Пойми, что мы не телепаты. smile.gif
O'kay?
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.