Файлы Турбо Паскаля

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

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

В качестве примера, воспроизведём здесь вариат уже представленного на сайте решения следующей сформулированной мною на лекции задачи:

Задача "Треугольник". Написать программу, которая формирует по заданному натуральному N, текстовый файл следующей треугольной структуры :
1
2 3
4 5 6
7 8 9 10
...
Каждая следующая строка этого файла содержит на один элемет больше предыдущей, а последней считается та, в которую попадёт заданное натуральное N.

  1. Program txtFileOut;
  2.    // обошлись без переменных!
  3.     procedure triangle(n:integer; var f: Text);
  4.         Var i, inLn, lnCount: LongInt;
  5.     Begin
  6.         i:=1;  // значение первого элемента
  7.         inLn:=1; // число элементов в 1-й строке
  8.         Repeat
  9.            For lnCount:=1 to inLn Do Begin  // формируем строку
  10.               Write(f,i:3); Inc(i)
  11.            End;
  12.            WriteLn(f); // к следующей строке ...
  13.            Inc(inLn); //... в которой будет на один элемент больше
  14.         Until i>n;
  15.     End;
  16.  
  17. Begin
  18.    triangle(20, output);
  19.    readln;
  20. End.

Заметьте, для проверки решающей задачу процедуры в главной программе использован стандартный текстовый файл output. Это позволяет обойтись без его описания, привязки и открытия в главной программе. Правда, результат мы получим на экране, а не на диске. Запустите и убедитесь что всё работает!
Теперь измените главную программу с тем, чтобы файл выводился на диск. И снова проверьте!

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

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

Задача fl2. В Блокноте набран и сохранён под именем 'ttt.txt' текстовый файл, содержащий по одному символу (Char) в каждой строке. Длина файла не превышает 255. Написать программу, которая читает этот файл как типизированный и формирует объединяющий все его символы стринг.

Задача fl3. В Блокноте набран и сохранён под именем 'D.txt' текстовый файл, содержащий по одному символу (Char) в каждой строке. Длина файла произвольна. Написать программу, которая читает этот файл и формирует на его основе файл 'R.txt' в котором символы исходного файла расположены в обатном порядке.

Задача fl4. Описать функцию, которая по данному текстовому файлу определяет число содержащихся в ней строк.

Задача fl5.Для задаваемых M, N <= 20 сформировать матрицу A(M,N) из случайных натуральных значений (меньших ста) и вывести её построчно (т.е. в "естественном" виде), в текстовый файл. Проверить результат вывода в Блокноте.

Задача fl6.Матрицу, сформированную в задаче fl5 ввести из файла и вывести в транспонированном виде на экран.

Никита, по условию, от нас

Никита, по условию, от нас требуется только записать символы в стринг

Валентин

По моей логике все сработает корректно, то есть
h#13#10 //прочитали очередной символ и перешли на следующую строку
e#13#10
l#13#10
l#13#10
o#13#10
#13#10
w#13#10
o#13#10
r#13#10
l#13#10
d#13#10
)#13#10

Вика

Что ты хотела этим сказать "Никита, по условию, от нас требуется только записать символы в стринг" ?

Никита

Мы не поймем друг друга...

Ну на мой взгляд, Никитина

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

Никита

Да ты прав, у нас же типизированный файл.... Прошу прощения

Вик, а именно в твоем

Вик, а именно в твоем варианте решения задачи fl4 все верно выводит? мне кажется в функции нужно не
function fl4(name:string):byte;
,а так
function fl4(f:text):byte;
, т.е. не с именем файла работать

Ксения

Достаточно передавать в подпрограмму либо уже привязанную файловую переменную, либо имя физического файла ,
так что у Вики сработает )

А чем мой авс отличается, раз

А чем мой авс отличается, раз выражение типа текст нельзя преобразовывать к типу стринг?)) разъясни мне тогда,пожалуйста)

Ксения

пришли проблемный участок кода :)

Каждому из четверых добавляю

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

Валерий Шахамболетович

Дайте пожалуйста еще немного времени для решения 3 и 6 задач.

Задача fl3

  1. program Record_number_in_reverse;
  2.   var i:longint;
  3.       c:char;
  4.       f,d:file of char;
  5. begin
  6.    assign(f,'F.txt');
  7.    reset(f);
  8.    assign(d,'D.txt');
  9.    rewrite(d);
  10.    i:=1;
  11.    while true do begin
  12.          seek(f,filesize(f)-i);
  13.          read(f,c);
  14.          write(d,c,#13);
  15.          inc(i);
  16.         if filesize(f)-i<0 then break;
  17.   end;
  18.   close(f);
  19.   close(d);
  20. end.

Нет, не верно, Валентин. В

Нет, не верно, Валентин. В чём элементарно убедиться на практике.

fl3

  1. program fl3;
  2. var d,f:file of char;
  3.       x:char;
  4.       dln:longint;
  5. begin
  6.   assign(d,'D.txt');
  7.   assign(f,'F.txt');
  8.   reset(d);
  9.   rewrite(f);
  10.   dln:=filesize(d);
  11.   while (dln<>0) do begin
  12.     read(d,x);
  13.     seek(f,dln);
  14.     write(f,x);
  15.     dec(dln);
  16.   end;
  17.   close(d);
  18.   close(f);
  19. end.

Будет ли это работать? У меня оно записывает в верной последовательности, но на одной строке 2 символа

Нет, и у Вас, Дмитрий, не то.

Нет, и у Вас, Дмитрий, не то.

Валерий Шахамболетович

Скажите пожалуйста, почему не правильно, где ошибка?

Исходите, Валентин, из двух

Исходите, Валентин, из двух "аксиом":
1. Переход на новую строку БЛОКНОТ обеспечивает ТОЛЬКО по комбинации #13#10
2. Совпадение ответа с ожидаемым НИКОГДА не доказывает правильность программы.

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

Валерий Шахамболетович

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

  1.  write(d,c,#13);

на строку:
  1.  if (c<>#13) and (c<>#10) then write(d,c,#13,#10);

А зачем все так сложно?

Валентин, зачем ты одиночный оператор "всунул" в составной? then begin write(d,c,#13,#10) end;
Можно ведь обойтись простой комбинацией then write(d,c,#13,#10);
Еще мне совсем не понятная твоя конструкция цикла: while true do begin... с условием на break.
Куда поэлегантней выглядит конструкция repeat ... until.
Может во всем этом есть скрытый смысл? Тогда прошу изложить его для всех :)

Дмитрий

У меня там так и написано  then write(d,c,#13,#10);
Да я понимаю что конструкция while true do begin не красивая, приведенный тобой вариант, как ты выразился "элегантнее" выглядит, но однако и он не верен... Речь сейчас идет о том что: чтение символов идет с конца, и конструкция #13, #10 в файл записывается в обратном порядке(т.е. не правильно) , но блокнот видит и распознает эти символы так как необходимо, однако все равно программа уже является неверной, вот поэтому я и решил эти символы включить в новый файл в нужном порядке.

Так же, можно поменять

Так же, можно поменять символы #13 и #10 местами:

  1. if c=#10 then c:=#13 else if c=#13 then c:=#10;
  2. write(d,c);

До твоего комментария было

До твоего комментария было написано иначе, исправился, молодец :)

Дмитрий

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

fl5

Не знаю, зачтена или нет, но вот задачка fl5

  1. program fl6;
  2. var a:array [1..20, 1..20] of byte;
  3.       i,j,m,n:byte;
  4.       mass_f:text;
  5. begin
  6.   randomize;
  7.   write('Введите размерность: ');
  8.   readln(m,n);  //ввод размерности
  9.   assign(mass_f,'mass_f.txt');
  10.   rewrite(mass_f);
  11.   for I := 1 to m do begin
  12.     for J := 1 to n do begin
  13.       a[i,j]:=random(100);  //генерация числа
  14.       write(mass_f,a[i,j], ' ');  //запись его в файл
  15.       write(a[i,j], ' ');  //вывод на экран
  16.     end;
  17.     writeln(mass_f);  //переход в файле на новую строку
  18.     writeln;  //переход на новую строку на экране
  19.   end;
  20.   close(mass_f);
  21. end.

Сохранение идет в файл mass_f.txt

fl6

Мое решение для квадратных матриц.
Суть:
1) Сначала выводим матрицу из текстового файла, подсчитывая количество строк (первая часть кода).
2) Перематываем файл в начало, путем открытия и закрытия.
3) Формируем массив на основе файла:
3.1) Считываем целиком строку.
3.2) Так как матрица квадратная, то в одной строке элементов = размерности, отсюда разделителей в строке = (размерность - 1 штук)
3.3) Ищем первый разделитель (в моем случае это одиночный пробел).
3.4) Копируем основную строку с 1 элемента до первого разделителя.
3.5) Преобразуем полученную дополнительную строку в число.
3.6) Удаляем из основной строки нашу вспомогательную.
3.7) Вне цикла преобразуем основную строку в число (в ней останется последнее число, без разделителей).
4) Транспонируем полученный массив.
5) Печатаем на экране.

  1. program fl6;
  2. var a:array [1..20, 1..20] of byte;
  3.       x,strok,i,j,p:byte;
  4.       mass_f:text;
  5.       s,k:string;
  6.       n:integer;
  7. begin
  8.   assign(mass_f,'mass_f.txt');
  9.   reset(mass_f);
  10.   strok:=0;
  11.   while (not eof(mass_f)) do begin
  12.     readln(mass_f,s);
  13.     writeln(s);
  14.     inc(strok);  //число строк в матрице
  15.   end;
  16.  
  17.   writeln;
  18.   writeln('Результат:');
  19.   writeln;
  20.   close(mass_f);
  21.   reset(mass_f);  //перемотка в начало
  22.  
  23.   for I := 1 to strok do begin
  24.     readln(mass_f,s);
  25.     for J := 1 to strok-1 do begin
  26.       p:=pos(' ',s);
  27.       k:=copy(s,1,p);
  28.       val(k,a[i,j],n);
  29.       delete(s,1,p);
  30.     end;
  31.     val(s,a[i,strok],n);
  32.   end;
  33.  
  34.   for I := 1 to strok do begin
  35.     for J := 1 to strok do if (i+j>i*2) then begin
  36.       p:=a[i,j];
  37.       a[i,j]:=a[j,i];
  38.       a[j,i]:=p;
  39.     end;
  40.   end;
  41.  
  42.   for I := 1 to strok do begin
  43.     for J := 1 to strok do write(a[i,j], ' ');
  44.     writeln;
  45.   end;
  46.   close(mass_f);
  47. end.

Дмитрий

Объясни, что за процедура  val(k,a[i,j],n); ?

Валентин,процедура Val(s,p,v)

Валентин,процедура Val(s,p,v) преобразовывает строковое значение (s) в его числовое представление, как это происходит при чтении из текстового файла с помощью Read. При этом, если это правильная запись числа, то в v записывается 0. Значение числа p должно быть типа Integer или Real, что не учтено в программе Дмитрия, значит программа уже сработает неверно. Потому что неправильно указан тип одного из параметров в процедуре

Валентин, Виктория

procedure Val (S: <строковый тип>; var V; var Code: Integer);
S - строка типа string или PChar с символьным представлением числа;
V - переменная целого или вещественного типа для записи двоичного представления числа;
Code - номер неправильного символа (0 - если изображение числа правильное) .

В моем случае в качестве V выступает элемент массива типа byte, a byte - тип целых чисел => все параметры верные.

Нет, Дмитрий, с вещественным

Нет, Дмитрий, с вещественным типом согласна, а вот с байтовым типом нет. Только Integer. Если у тебя все сработало и матрица получилась в таком виде, которое требуется, то тут мне кажется только вина версии паскаля

Ок. Зайдем в официальную

Ок. Зайдем в официальную справку и посмотрим о процедуре val, что мы видим
...
V is an integer-type or real-type variable.
Code is a variable of type Integer
...
То, что V должна быть строго integer, не написано. Integer-type дословно, переводится как целый тип а не как тип integer, иначе это было бы строго оговорено, как например с Code, где все строго.

Еще раз, integer-type и type Integer совсем разные вещи. Первое - все целые числа, второе - простой тип.

Дмитрий, я не знаю в какой

Дмитрий, я не знаю в какой среде пишешь коды ты, но у меня только Паскаль ABC, и свои выводы я делаю исходя от работы именно в этой версии. У меня с типом byte не работало. Но я учту твои замечания по поводу типов в этой процедуре

Поменяй тип массива на

Поменяй тип массива на integer и все, пишу я в Delphi XE2.

Я почитал справку по паскалю

Я почитал справку по паскалю abc, там написано так:
(для одного варианта val из 10)
procedure Val(s: string; var value: byte; var err: integer);
тип byte должен работать!

Можешь посмотреть здесь

Дмитрий

Задана произвольная матрица, размерности m*n (по условию 5 задачи), а не квадратная, в этом и вся суть задачи, определить размерность...

Возможен и такой вариант, что

Возможен и такой вариант, что размерность должна не вводиться с клавиатуры, а быть уже заданной. Может быть, это облегчает работу программы

Виктория

Да, возможно этот вариант наиболее оптимален с точки зрения кода программы, допустим мы изменим решение задачи fl5 и передадим в первую строчку файла (прежде чем введем сам массив) информацию о размерности массива:

  1. ...
  2. write('Vvedite razmer massiva: ');
  3. readln(m,n);
  4. writeln(f,m,n);
  5. ....

тогда это нам позволит считать размерность в задаче fl6 и тем самым облегчить себе работу...

Задача fl6

  1. program Record_in_the_file;
  2. const lim=20;
  3.  type Ar=array[1..lim,1..lim]of byte;
  4.  var m,n,i,j:byte;  a,q:Ar; f:text;
  5. begin
  6.  assign(f,'M.txt');
  7.  reset(f);
  8.  readln(f,m,n);
  9.   while not(eof(f)) do begin
  10.    for i:=1 to m do begin
  11.     for j:=1 to n do begin
  12.      read(f,a[i,j]);
  13.     end;//for i
  14.     readln(f);
  15.    end; //for j
  16.   end;//while
  17.   for i:=1 to n do begin
  18.    for j:= 1 to m do begin
  19.     q[i,j]:=a[j,i];
  20.    end;//for i
  21.   end;//for j
  22.   for i:=1 to n do begin
  23.    for j:=1 to m do begin
  24.     write(q[i,j]:3);//Вывод результирующего массива
  25.    end; //for i
  26.   writeln;
  27.  end;//for j
  28.  close(f);
  29. end.

Облегчаем, облегчаем...

Любите вы, облегчать все... Записав в начало файла размер массива, вы тем самым нарушаете конструкцию самого массива в файле! Объясню на примере:
Пусть размеры будут 3 на 3
Выходной файл получится
3 3
1 2 3
4 5 6
7 8 9
Этот файл не является матрицей, что противоречит условию задачи 5!

Доделанная версия fl6

Вот доделанная версия, работает для размерности MxN
Пришлось добавить вспомогательный массив и чуть подумать над длинною строки.
Количество элементов в строки столько, сколько в ней разделителей +1.

  1. program fl6;
  2. var a,b:array [1..20, 1..20] of byte;
  3.       x,strok,chisel,i,j,p:byte;
  4.       mass_f:text;
  5.       s,k:string;
  6.       n:integer;
  7. begin
  8.   assign(mass_f,'mass_f.txt');
  9.   reset(mass_f);
  10.   strok:=0;
  11.   while (not eof(mass_f)) do begin
  12.     readln(mass_f,s);
  13.     writeln(s);
  14.     inc(strok);  //число строк в матрице
  15.   end;
  16.   chisel:=0;
  17.   while (pos(' ',s)<>0) do begin
  18.     p:=pos(' ',s);
  19.     inc(chisel);
  20.     delete(s,1,p);
  21.   end;
  22.   inc(chisel);  //число чисел в строке
  23.  
  24.   writeln;
  25.   writeln('Результат:');
  26.   writeln;
  27.   close(mass_f);
  28.   reset(mass_f);  //перемотка в начало
  29.  
  30.   for I := 1 to strok do begin
  31.     readln(mass_f,s);
  32.     for J := 1 to chisel-1 do begin
  33.       p:=pos(' ',s);
  34.       k:=copy(s,1,p);
  35.       val(k,a[i,j],n);
  36.       delete(s,1,p);
  37.     end;
  38.     val(s,a[i,chisel],n);
  39.   end;
  40.  
  41.   for I := 1 to chisel do begin
  42.     for J := 1 to strok do b[i,j]:=a[j,i];
  43.   end;
  44.  
  45.   for I := 1 to chisel do begin
  46.     for J := 1 to strok do write(b[i,j], ' ');
  47.     writeln;
  48.   end;
  49.   close(mass_f);
  50. end.

Дмитрий

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

Валентин

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

Дмитрий, твоя программа

Дмитрий, твоя программа выводит неправильный результат: только первый столбец

Дмитрий

И чему же нас здесь учат?

Дмитрий, нас конечно учат

Дмитрий, нас конечно учат более высокому, но не писать огромные коды, когда можно составить код так, что он будет более компактен и результат будет верен.

Виктория

Если у тебя одна строка, один столбец программа и выведет. У мне работает все верно.

Валентин

Явно не конструкциям while true do begin ... if B then break;

нет, у меня матрица

нет, у меня матрица размерности 3 на 3

Дмитрий, Виктория

Мне кажется, что нам меньше нужно засорять форум своими высказываниями, которые фактически не несут в себе информационной пользы...

Виктория

Интересно посмотреть, что за матрица там такая "волшебная".