#13 Филе из FILE. часть 2

Вступление

Здравствуйте!

Гм, сегодня вышла не радостная рассылка. Вызвано это одной причиной: поехал на работу перепрошивать BIOS на матери, а её свиснули из машины :((( обидно...
Это происшествие несколько выбило меня из колеи, а ведь даже что бы выпускать расылку нужно какое-то вдохновление, вот выпуск и подзадержался :(

Теория

Сегодня мы поговорим о бестиповых файлах. Бестиповые файлы позволяют записывать произвольные данные в файл.

Для создания файловой переменной, мы должны указать просто слово file:

var
F : file;
Принцип работы с бестиповыми файлами такой же, как и с типовыми: сначала связываем файловую переменную с файлом с помощью процедуры Assign. Затем открываем его с помощью процедур Reset или Rewrite. А после окончания работы он должен быть закрыт процедурой Close.

Однако не всё так просто, как хотелось бы :( Помните в прошлый раз я написал дополнительные параметры к функциям Rewrite и Rest ? Для типовых файлов эти параметры были не важны, а вот для бестиповых.... так, что читайте ниже дополнительное описание этих процедур:

  • procedure Reset(var F : File; Recsize: Word );
  • procedure Rewrite(var F: File ; Recsize: Word );
в обоих случаях параметр Recsize задаёт число байтов, считываемых из файла или записываемых в него за одно обращение. Минимальное значение Recsize 1 байт, максимальное - 64 К байт. По умолчанию он равен 128 байтам.

А вот запись и чтение осуществляется другими процедурами.

procedure BlockRead(var F: File; var Buf; Count: Word; var Result: Word);
Эта процедура служит для чтения из файла. F - файловая-переменная. Buf - переменная любого типа, Count - число блоков, которое нужно считать в Buf. Необязательный параметр Result - число успешно прочитанных блоков. В случае успеха Result = Count. Например считаем из файла строку:
program test;

var
  FromF: file;
  Buf : string;

begin
  Assign(FromF, 'C:\1.txt');
  Reset(FromF, 1);
  BlockRead (FromF, Buf, SizeOf(Buf));
  Close(FromF)
end.
Мы не используем параметр Result при вызове BlockRead. Размер нашего буффера можно сосчитать с помощью уже известной функции sizeof. Кстати, если вы напишите после этого строку write (buf), то увидите совсем не строку из файла, а нечто на неё похожее. BlockRead до лампочки читаете вы из файла строку или вещёственное число, она просто читает заданное ей количество байт и записывает их по аддресу переменной buf. Т.е. мы дали команду считать 256 байт (SizeOf(Buf) = 256) и записать результат в Buf. BlockRead не будет разбираться, что Buf у нас это строка, и не запихнёт в Buf[0] размер строки. В buf[0] будет первый байт, находящийся в файле! А это может быть, например нулевой символ и тогда buf[0] = #0 и на экран ничего не выведется.

Ну и соответственная процедура для записи в файл:

procedure BlockWrite(var f: File; var Buf; Count: Word; var Result: Word);
Соответственно эта процедура пишет в файл F, Count байт из Buf. Result так же является не обязательным параметром, и в нём возвращается число блоков успешно записанных процедурой.

Например запишем в файл строку, которую ввёл пользователь:

var
  FromF: file;
  Buf : string;

begin
  ClrScr;
  Assign(FromF, 'C:\2.txt');
  rewrite(FromF, 1);
  readLn (buf);
  BlockWrite(FromF, Buf, SizeOf(Buf));
  Close(FromF)
end.
BlockWrite так же по барабану строка это у нас или нет. Поэтому в результате создасться файл, размером в 256 байт. Даже если вы ввели строку из 3-х символов, размер не изменится. При этом первый байт в файле - это символ с номером, равным длинне строки.

Однако рамер одного символа = 1 байту, размер строки = buf [0], поэтому преобразовав вызов процедуры в такой, мы получим нужный результат (т.е. такой результат, что бы размер файла соответствовал размеру строки + 1):

BlockWrite(FromF, Buf, ord (Buf[0]) + 1);
Кстати практически все файлы являются не типизированными. Откройте, например, любой bmp через текстовый редактор. Вот так выглядят несколько строк любимых Облачка.bmp:
BM:_ : ( А р   _ + - A A +н{ _¦Д +нs _н{ _+Ф _¦{ _¦М _+М _¦Ь я_+ яч_ ч¦е ч++ ч+н ч+е ўяч ячч _+Ь +¦{ _нs я_¦ ч+¦ ўўў ўяя _+Д ўўя ч+¦ яч+ ч+¦ ч¦Ь яч+ я++ яя_ ўч_ ўя_ ўўч _¦s я+¦ ч+Ь ўч+ я_+ я_+ я+¦ _ўў ч+Ф _¦Ф я+¦ ч¦н __ў ўў_ ў_ў ў_+ ўч+ ___ ч+н ч¦Ф _ў_ я+н ч+Ь ч+М ў__ я+н ч¦М ч¦Д я+е
а ведь и не скажешь, что картинка :)

Программа

Сегодня мы не будем особо выдумывать и напишем очередную програмку, которая копирует один файл в другой. Естесственно мы будем считать, что оба файла не типизированные. И как всегда :) скопируем autoexec.bat в autoexec.txt:

program CopyFile;

var
  FromF, ToF: file;
  NumRead, NumWritten: Word;
  Buf: array [1..100] of Char;

begin
  Assign(FromF, 'C:\autoexec.bat');
  Reset(FromF, 1);
  Assign(ToF, 'C:\autoexec.txt');
  Rewrite(ToF, 1);

  repeat
    BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
    BlockWrite(ToF, Buf, NumRead, NumWritten)
  until (NumRead = 0) or (NumWritten <> NumRead);

  Close(FromF);
  Close(ToF)
end.
Здесь я уже использую параметры, которые возращают число успешно прочитанных символов. После вызова
BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
в NumRead у нас окажется число прочитанных байт, потом мы вызываем BlockWrite:
BlockWrite(ToF, Buf, NumRead, NumWritten)
Поэтому даже если мы прочитали меньше, чем sizeof (Buf) (ну ка скажите моментом, чему равено sizeof (buf)? если вы потратили на это больше двух секунд, значит вам нужно больше заниматься :). Так вот даже если мы прочитали меньше, чем sizeof (Buf), то запишем мы ровно столько, сколько прочитали.

[Назад] [Содержание] [Дальше]
Hosted by uCoz