====== Операции над типизированными файлами в Турбо Паскале ====== Типизированные файлы называются таковыми потому, что для них определён тип данных записи. В них все записи являются одного типа (иными словами, однородными), т.е. **file of тип_данных**. Такие файлы содержат информацию в бинарном виде и (нормальный) человек прочесть их не сможет. Типом данных может быть любой тип данных Паскаля за исключением типа **file**. Рассмотрим на примере тип **запись** (record). Тип запись определяется заранее (уже известен). Например: type TInfoRecord = record { Определяем тип записи TInfoRecord } Num: integer; { порядковый номер, числовой тип integer } Name: string[20]; { Имя, до 20 символов } Tel: string[12]; { Телефон, до 12 символов } end; Позиция при открытии (существующего) файла: |*|0|1|2|3|4| В файле может ещё не быть записей, если он едва был создан. Не забывайте, что нумерация записей начинается **с нуля**. ===== Поиск записи ===== Алгоритм:\\ - установить позицию на начало, если необходимо (не нужно когда только что открыли файл для чтения) - проверять каждую запись по нужному критерию (имя, телефон и т.д.) - продолжать с пункта 2 пока не конец файла. Пока не конец файла Считать запись Проверить, искомая ли. Если да, то что-то делать (вывести на экран, к примеру). конец цикла ===== Добавление записи ===== Чтобы добавить запись в файл, необходимо сначала установить позицию в конец файла командой Seek ,а затем производить запись с помощью Write. Позиция в конце файла |0|1|2|3|4|*| Производим запись. Теперь добавилась ещё одна. |0|1|2|3|4|5|*| type TStudentInfo = record Name: string[30]; group: string[10]; Exams: array[1..5] of byte; end; var F: file of TStudentInfo; st: TStudentInfo; i: integer; begin Assign (f, 'students.dat'); {$I-} Reset (F); { попытка открыть файл } {$I+} if IOresult <> 0 then { при неудаче создаём пустой файл } Rewrite (F); Seek (F, FileSize (F)); { становимся в конец файла } With st do { заполняем данные записи } begin write ('Имя студента: '); readln (Name); write ('Группа: '); readln (group); writeln ('Оценки по пяти экзаменам:'); for i := 1 to 5 do readln (Exams[i]); end; Write (F, st); { записываем запись в файл } Close (F); end. ===== Правка записи ===== Чтобы **поправить** N-ю запись, надо стать на позицию этой записи с помощью //Seek (F, recN)//, а затем производить запись. Аналогично предыдущему примеру, только вместо //Seek (F, FileSize(F))// пишем //Seek (F, recN)//. При этом надо следить за тем, чтобы не возникло ошибки при введении несуществуещего номера записи, чтобы программа не завершилась с ошибкой. |0|1|*|2|3| Здесь курсор установлен на позиции 2, готовой для чтения и правки записи под номером 2. После того, как изменили запись, позиция продвинулась вперёд. type TStudentInfo = record Name: string[30]; group: string[10]; Exams: array[1..5] of byte; end; var F: file of TStudentInfo; st: TStudentInfo; recN, i, MaxRecords: integer; exists: boolean; begin Assign (f, 'students.dat'); {$I-} Reset (F); {$I+} if IOresult <> 0 then halt; MaxRecords := FileSize(F); if MaxRecords = 0 then begin writeln ('Записей нет!'); exit; end; repeat write ('Введите номер записи для замены [0..', MaxRecords-1, ']: '); readln (recN); {$I-} Seek (F, recN); { пытаемся установиться на нужную запись } {$I+} exists := (IOresult = 0) and (recN < MaxRecords); { признак успеха } if Not exists then writeln ('Вы ввели номер несуществующей записи! Попытайтесь снова.'); until exists; With st do begin write ('Имя студента: '); readln (Name); write ('Группа: '); readln (group); writeln ('Введите оценки по 5 экзаменам:'); for i := 1 to 5 do readln (Exams[i]); end; Write (F, st); { записываем запись в файл } Close (F); end. ===== Поиск и правка записи ===== Если надо найти запись и исправить ее, надо: - установить позицию на начало, если необходимо (не надо когда только открыли файл для чтения) - проверять каждую запись по нужному критерию (имя, телефон и т.д.) - вернуться на одну позицию назад:\\ Seek(F,FilePos(F)-1), т.к. после чтения записи с файла позиция уже продвинулась на следующую; - внести изменения в записи и затем производить запись в файл. - продолжать с пункта 2 пока не конец файла. type TStudentInfo=record Name: string[30]; Kurs: string[20]; Exams: array[1..5] of byte; end; var f: file of TStudentInfo; st: TStudentInfo; who: string[30]; found: boolean; begin write('Кого ищем? '); readln(who); if who='' then exit; assign(f,'students.dat'); {$I-} reset(F); {$I+} found:=false; if IOresult=0 then with st do while Not EOF(F) do begin read(F,st); if name=who then { нашли такого/ую } begin write('Заменить на фамилию: '); readln(name); found:=true; seek(F,FilePos(F)-1); { вернуться на 1 позицию обратно, т.е. на позицию того, что надо заменять } write(f,st); break; { убрать это, если известно, что таких несколько } end; end; close(f); if Not Found then writeln(Who,' не найден. Ха-ха') else writeln(Who,' найден и заменен.'); writeln(#13#10'Жми Enter'); readln; end. ===== Удаление записи ===== ==== Удаление последовательности записей ==== Для удаления (отсечения) последовательности записей, начиная с текущей позиции (можно установить с //Seek//), применяют процедуру //Truncate//. Процедура Truncate( var f ) устанавливает в текущей позиции признак конца файла и удаляет (стирает) все последующие блоки. ==== Удаление одной записи ==== Для удаления одной **неконечной** записи требуется воспользоваться созданием дополнительного файла, в который запишутся все записи, кроме заданной. Записываем записи 0..i-1, пропускаем запись i, а потом дописываем записи i+1..N. === Другой способ (хитрый) === Скопировать последнюю запись на место i-й, а потом отсечь последнюю с помощью //Truncate//. ===== Вставка записи ===== Для вставки записи также требуется воспользоваться созданием дополнительного файла, в который запишутся все записи: * сначала записи 1..i-1 * затем вставляемая запись * затем записи i, .. N