265 lines
17 KiB
HTML
265 lines
17 KiB
HTML
|
||
<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<T>".<br>
|
||
Но она также подходит и для обучения основам "BlockFileOf<T>".
|
||
<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<T>":</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<T>; </t>
|
||
<br><t style="margin-left: 10px">f := new BlockFileOf<T>; // В отличии от file of T - BlockFileOf<T> нужно всегда инициализировать </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<T>; </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<byte>('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<T>":</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<integer>('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<T>" все 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<T>":</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<integer>('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<T>.ToSeq" работает так же, как и "(file of T).ReadElements" (если не считать более продвинутой защиты от дурака):<br>
|
||
Они оба читают файл по одному элементу и после каждого из них проверяют, не достигнут ли конец файла.<br>
|
||
<br>
|
||
Но в "BlockFileOf<T>" есть альтернатива - "ToSeqBlocks".<br>
|
||
Эта функция читает всё из файла блоками заданной длины в байтах. Если не задавать длину, данные будут читаться блоками по 4 килобайта.<br>
|
||
В нашем случае, "integer" занимает 4 байта в памяти, значит в каждом блоке по 4 КБ поместится 1024 элемента типа "integer"<br>
|
||
(Объём типа T можно узнать из свойства "BlockFileOf<T>.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<integer>('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<r1>('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<T>" подходит к этому с другой стороны.<br>
|
||
Когда вы первый раз инициализируете переменную типа "BlockFileOf<r1>" -<br>
|
||
объём в памяти, занимаемый переменными типа "r1", вычисляется и сохраняется во внутреннее статическое поле<br>
|
||
(Его можно получить через свойство "TSize")<br>
|
||
И когда вызывается функция "Read" - "BlockFileOf<T>" читает из файла столько байт, сколько занимают переменные типа "r1",<br>
|
||
А потом копирует содержимое полученного массива байт в результат.<br>
|
||
<br>
|
||
То есть, "file of T" читает три блока, а "BlockFileOf<T>" только один.<br>
|
||
И когда объём данных одинаковый - количество блоков очень важный фактор.<br>
|
||
Поэтому "BlockFileOf<T>" будет быстрее.<br>
|
||
И размер одного блока не ограничивается размером одной переменной типа "r1".<br>
|
||
"Read(10)", к примеру, прочитает одним блоком то, что "file of T" читал бы как 30 блоков.<br>
|
||
<br>
|
||
Ну и, конечно, всё то же самое касается и "Write".<br>
|
||
<hr />
|
||
</div>
|
||
|
||
|
||
</body>
|
||
|
||
</html> |