This repository has been archived on 2024-12-25. You can view files and clone it, but cannot push or open issues or pull requests.
2024-03-10 20:32:51 +03:00

265 lines
17 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
.code_block {
background: #c0c0c0;
padding: 5px;
padding-right: 20px;
border: solid 1px black;
}
</style>
<script type="text/javascript">
function toggle_show(id) {
document.getElementById(id).style.display = document.getElementById(id).style.display == 'none' ? 'block' : 'none';
}
</script>
</head>
<body>
<font size="3"><a href="../Справка.html"><=</a></font><br>
<br>
Основной упор данной страницы - сравнение "file of T" и "BlockFileOf&ltT>".<br>
Но она также подходит и для обучения основам "BlockFileOf&ltT>".
<hr />
<p onClick="toggle_show('decl')"><font size="4" color="008000" style="cursor: pointer">Объявление</font></p>
<div id=decl style="display: none">
<font size="3">"file of T":</font>
<p class=code_block>
<t style="margin-left: 00px">begin </t>
<br><t style="margin-left: 10px">var f: file of T; </t>
<br><t style="margin-left: 10px">Assign(f, 'temp.bin'); </t>
<br><t style="margin-left: 00px">end. </t>
</p>
<font size="3">"BlockFileOf&ltT>":</font>
<p class=code_block>
<t style="margin-left: 00px">uses BlockFileOfT; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">begin </t>
<br><t style="margin-left: 10px">var f: BlockFileOf&ltT>; </t>
<br><t style="margin-left: 10px">f := new BlockFileOf&ltT>; // В отличии от file of T - BlockFileOf&ltT> нужно всегда инициализировать </t>
<br><t style="margin-left: 10px">f.Assign('temp.bin'); </t>
<br><t style="margin-left: 00px">end. </t>
</p>
<font size="3">Последнее можно сократить:</font>
<p class=code_block>
<t style="margin-left: 00px">uses BlockFileOfT; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">begin </t>
<br><t style="margin-left: 10px">var f := new BlockFileOf&ltT>; </t>
<br><t style="margin-left: 10px">f.Assign('temp.bin'); </t>
<br><t style="margin-left: 00px">end. </t>
</p>
<font size="3">Или ещё больше сократить:</font>
<p class=code_block>
<t style="margin-left: 00px">uses BlockFileOfT; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">begin </t>
<br><t style="margin-left: 10px">var f := new BlockFileOf&ltbyte>('temp.bin'); </t>
<br><t style="margin-left: 00px">end. </t>
</p>
<hr />
</div>
<p onClick="toggle_show('io_basics')"><font size="4" color="008000" style="cursor: pointer">Основы записи/чтения</font></p>
<div id=io_basics style="display: none">
<font size="3">"file of T":</font>
<p class=code_block>
<t style="margin-left: 00px">begin </t>
<br><t style="margin-left: 10px">var f: file of integer; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">Rewrite(f, 'temp.bin'); </t>
<br><t style="margin-left: 10px">f.Write( </t>
<br><t style="margin-left: 20px">1,2,3,4,5 </t>
<br><t style="margin-left: 10px">); </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">Reset(f); </t>
<br><t style="margin-left: 10px">loop 5 do </t>
<br><t style="margin-left: 20px">f.Read.Print; </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">end. </t>
</p>
<font size="3">"BlockFileOf&ltT>":</font>
<p class=code_block>
<t style="margin-left: 00px">uses BlockFileOfT; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">begin </t>
<br><t style="margin-left: 10px">var f := new BlockFileOf&ltinteger>('temp.bin'); </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">f.Rewrite; </t>
<br><t style="margin-left: 10px">f.Write( </t>
<br><t style="margin-left: 20px">1,2,3,4,5 </t>
<br><t style="margin-left: 10px">); </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">f.Reset; </t>
<br><t style="margin-left: 10px">f.Read(5).Print; </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">end. </t>
</p>
В случае с "BlockFileOf&ltT>" все 5 элементов читаются одним блоком памяти.<br>
В то время как "file of T" читает по одному элементу.<br>
<hr />
</div>
<p onClick="toggle_show('to_seq')"><font size="4" color="008000" style="cursor: pointer">Перечисление всех элементов в файле</font></p>
<div id=to_seq style="display: none">
<font size="3">"file of T":</font>
<p class=code_block>
<t style="margin-left: 00px">begin </t>
<br><t style="margin-left: 10px">var f: file of integer; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">Rewrite(f, 'temp.bin'); </t>
<br><t style="margin-left: 10px">f.Write( </t>
<br><t style="margin-left: 20px">1,2,3,4,5 </t>
<br><t style="margin-left: 10px">); </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">Reset(f); </t>
<br><t style="margin-left: 10px">f.ReadElements.Print </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">end. </t>
</p>
<font size="3">"BlockFileOf&ltT>":</font>
<p class=code_block>
<t style="margin-left: 00px">uses BlockFileOfT; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">begin </t>
<br><t style="margin-left: 10px">var f := new BlockFileOf&ltinteger>('temp.bin'); </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">f.Rewrite; </t>
<br><t style="margin-left: 10px">f.Write( </t>
<br><t style="margin-left: 20px">1,2,3,4,5 </t>
<br><t style="margin-left: 10px">); </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">f.Reset; </t>
<br><t style="margin-left: 10px">f.ToSeq.Print; </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">end. </t>
</p>
"BlockFileOf&ltT>.ToSeq" работает так же, как и "(file of T).ReadElements" (если не считать более продвинутой защиты от дурака):<br>
Они оба читают файл по одному элементу и после каждого из них проверяют, не достигнут ли конец файла.<br>
<br>
Но в "BlockFileOf&ltT>" есть альтернатива - "ToSeqBlocks".<br>
Эта функция читает всё из файла блоками заданной длины в байтах. Если не задавать длину, данные будут читаться блоками по 4 килобайта.<br>
В нашем случае, "integer" занимает 4 байта в памяти, значит в каждом блоке по 4 КБ поместится 1024 элемента типа "integer"<br>
(Объём типа T можно узнать из свойства "BlockFileOf&ltT>.TSize", или с помощью sizeof(T) )<br>
В случае с пятью элементами это едва ли даст преимущество, но если записывать и считывать сразу большое количество элементов - считывание блоками будет намного быстрее:
<p class=code_block>
<t style="margin-left: 00px">uses BlockFileOfT; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">begin </t>
<br><t style="margin-left: 10px">var f := new BlockFileOf&ltinteger>('temp.bin'); </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">f.Rewrite; </t>
<br><t style="margin-left: 10px">f.Write( </t>
<br><t style="margin-left: 20px">1,2,3,4,5 </t>
<br><t style="margin-left: 10px">); </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">f.Reset; </t>
<br><t style="margin-left: 10px">var blocks := f.ToSeqBlocks; </t>
<br><t style="margin-left: 10px">var AsSeq := blocks.SelectMany(bl->bl); </t>
<br><t style="margin-left: 10px">AsSeq.Print; </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">end. </t>
</p>
"AsSeq := blocks.SelectMany(bl->bl)" здесь делает так, что хоть всё считывается из файла блоками,<br>
переменную "AsSeq" будет воспринимать как последовательность элементов, а не последовательность блоков.<br>
И - я расписал вывод как 3 строчки чтоб было виднее. Можно и сократить:
<p class=code_block>
<t style="margin-left: 10px">f.Reset; </t>
<br><t style="margin-left: 10px">f.ToSeqBlocks.SelectMany(bl->bl).Print; </t>
<br><t style="margin-left: 10px">f.Close; </t>
</p>
<hr />
</div>
<p onClick="toggle_show('bfo_record')"><font size="4" color="008000" style="cursor: pointer">Основное преимущество: сохранение записей (record)</font></p>
<div id=bfo_record style="display: none">
<p class=code_block>
<t style="margin-left: 00px">uses BlockFileOfT; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">type </t>
<br><t style="margin-left: 10px">r1 = record </t>
<br><t style="margin-left: 20px">b1: byte; </t>
<br><t style="margin-left: 20px">i: integer; </t>
<br><t style="margin-left: 20px">b2: byte; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 20px">constructor(b1: byte; i: integer; b2: byte); </t>
<br><t style="margin-left: 20px">begin </t>
<br><t style="margin-left: 30px">self.b1 := b1; </t>
<br><t style="margin-left: 30px">self.i := i; </t>
<br><t style="margin-left: 30px">self.b2 := b2; </t>
<br><t style="margin-left: 20px">end; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 20px">///Эта функция определяет то, как данную запись выведет на экран </t>
<br><t style="margin-left: 20px">function ToString: string; override := </t>
<br><t style="margin-left: 20px">$'r1(b1={b1}, i={i}, b2={b2})'; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">end; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">begin </t>
<br><t style="margin-left: 10px">var f := new BlockFileOf&ltr1>('temp.bin'); </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">f.Rewrite; </t>
<br><t style="margin-left: 10px">f.Write( </t>
<br><t style="margin-left: 20px">new r1(1,2,3) </t>
<br><t style="margin-left: 10px">); </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 10px">f.Reset; </t>
<br><t style="margin-left: 10px">writeln(f.Read); </t>
<br><t style="margin-left: 10px">f.Close; </t>
<br><t style="margin-left: 00px"> </t>
<br><t style="margin-left: 00px">end. </t>
</p>
Казалось бы, тот же самый код будет работать и для "file of T".<br>
Но вся разница находится в реализации:<br>
<br>
"file of T" в данном случае при вызове "Read" сначала прочитал бы названия и типы полей "r1" (через "System.Reflection"),<br>
а затем, по очереди, читал бы из файла значение того же типа, что и у поля ("byte", затем "integer" и снова "byte"),<br>
сохраняя прочитаные значения в соответствующих полях результата.<br>
<br>
А "BlockFileOf&ltT>" подходит к этому с другой стороны.<br>
Когда вы первый раз инициализируете переменную типа "BlockFileOf&ltr1>" -<br>
объём в памяти, занимаемый переменными типа "r1", вычисляется и сохраняется во внутреннее статическое поле<br>
(Его можно получить через свойство "TSize")<br>
И когда вызывается функция "Read" - "BlockFileOf&ltT>" читает из файла столько байт, сколько занимают переменные типа "r1",<br>
А потом копирует содержимое полученного массива байт в результат.<br>
<br>
То есть, "file of T" читает три блока, а "BlockFileOf&ltT>" только один.<br>
И когда объём данных одинаковый - количество блоков очень важный фактор.<br>
Поэтому "BlockFileOf&ltT>" будет быстрее.<br>
И размер одного блока не ограничивается размером одной переменной типа "r1".<br>
"Read(10)", к примеру, прочитает одним блоком то, что "file of T" читал бы как 30 блоков.<br>
<br>
Ну и, конечно, всё то же самое касается и "Write".<br>
<hr />
</div>
</body>
</html>