Вверх ↑
Пакеты 
HiAsm4
Windows 
Статьи - Массивы данных(Stream)

Массивы данных(Stream)
Что такое Stream
   Массивы данных или Stream - это набор из N-го количества байт, расположенных на жестком диске или в оперативной памяти компьютера. Причем величина N ограничена только физическими параметрами "железа", и может принимать значения от нескольких единиц до многих миллионов. Именно этим и являются все без исключения файлы: и музыка, и картинки, и программы, и текст - в общем все.

   Массив данных, как уже говорилось выше, это набор байт, т.е. число от 0 до 255, которое обычно представляют в шестнадцатиричном виде. Именно в таком виде потоковые данные и отображены в HiAsm:



   Слева расположена колонка, показывающая смещение текущей строки в шестнадцатеричном виде (у компонентов для работы с массивами данных это св-во Position). Затем по центру отображается сам массив по 16 байт в строке. И самая правая колонка – это представление массива байт в виде текста. На рисунке вы можете узнать заголовок этой статьи, однако загрузив в просмотрщик например EXE файл, в этом столбике вы увидите мешанину всевозможных символов и точек, даже отдаленно не напоминающих человеческий текст.

   Итак. Все данные, которыми оперирует пользователь, можно представить в одном виде - в виде массива байт. Благодаря этому, достаточно один раз написать компоненты для записи данных на диск, для отправки их между компьютерами по сети, для компрессии и декомпрессии, для шифрации и многого другого, чтобы в дальнейшем оперировать с одним типом Stream, а все остальные переводить в него по мере необходимости. Кроме того, массивы данных можно объединять и смешивать, создавая например свои собственные форматы файлов. Нужно всего лишь один раз изучить их работу и понять суть.
Работа с массивом данных
   Для хранения массивов данных на жестком диске используется компонент Файловый поток (FileStream). Для хранения в памяти - Данные в памяти (MemoryStream). Для записи и чтения данных компонент Данные в файл (DataToFile). Это основные компоненты для работы с типом Stream, поэтому с ними то и стоит познакомиться поближе.

   Разберем небольшой пример, суть которого – запись и считывание с диска файла, состоящего из BMP картинки и комментария к ней. Для этого нам понадобится программка для создания таких файлов с последующей записью на диск (Редактор), и программа для их просмотра (Просмотрщик).

   Откройте в конструкторе схему редактора:


Add(MainForm,82657,77,126)
{
Left=21
Top=105
}
Add(Button,27238,126,126)
{
Left=10
Top=10
Font=[Arial,8,0,0,1]
Caption="Save"
link(onClick,57202:doEvent1,[])
}
Add(Image,84162,364,175)
{
Left=90
Top=30
Width=295
Height=240
Color=16777215
}
Add(DoData,8617,245,231)
{
link(onEventData,69888:doPut,[])
link(Data,10768:Text,[])
}
Add(SDialog,63163,231,126)
{
link(onExecute,75081:doOpen,[])
}
Add(BitmapStream,60179,357,259)
{
link(Stream,14805215:Var3,[(363,219)])
link(Bitmap,84162:ImageBitmap,[])
}
Add(Hub,57202,182,126)
{
OutCount=4
link(onEvent1,63163:doExecute,[])
link(onEvent2,8617:doData,[(226,139)(226,237)])
link(onEvent3,60179:doWrite,[(217,146)(217,272)])
link(onEvent4,75081:doClose,[(273,153)(273,139)])
}
Add(DataToFile,69888,294,231)
{
Type=6
link(Stream,14805215:Var2,[])
}
Add(ClipboardHook,50190,315,175)
{
link(onBitmap,84162:doLoad,[(355,188)(355,181)])
}
Add(FileStream,75081,294,126)
{
Mode=1
}
Add(Edit,10768,245,175)
{
Left=90
Top=5
Width=295
Height=21
Font=[Arial,8,0,0,1]
Text=""
}
Add(GetDataEx,14805215,287,210)
{
link(Data,75081:Stream,[])
}

  • Итак, первое, с чего мы начинаем формирование файла, это с его открытия методом doOpen элемента FileStream (заметьте, что при записи файла его св-во Mode должно быть установленным в Write или ReadWrite). Эта операция создаст на диске пустой файл с указанным именем, в который в дальнейшем мы сможем записывать данные.
  • [img=Комментарий align=right]http://hiasm.com/xf/attach/wiki/stream_2.png[/img] Дальше записываем комментарий, введенный пользователем компонентом Данные в файл (DataToFile). Для этого необходимо указать ему идентификатор потока данных, в который будут записаны данные через точку Stream, а также тип данных в свойстве Type. Для нашего примера это будет dtAnsiString - строка с нулевым байтом на конце, который определяет её длину. Однако можно было указать и dtPString - это тоже строка, однако от dtAnsiString она отличается тем, что её первые два байта отведены под хранение количества содержащихся в ней символов. В нашем примере конкретный формат записи не принципиален. Так зачем вообще нужно знать о длине записываемой строки или о её конце? Ответ очевиден: когда мы "сваливаем" все данные в одну кучу, то становится не ясно где и что у нас начинается и где кончается. Например, нужно записать в файл помимо прочего две подряд идущие строки "привет" и "мир". Если не запоминать числа записанных символов или как-то не разделять их, то при считывании совершенно невозможно определить, записали ли мы два слова отдельно или одно "приветмир". Поэтому при записи комментария в файле у нас окажутся следующие данные: <Комментарий><0>
  • [img=Картинка align=right]http://hiasm.com/xf/attach/wiki/stream_3.png[/img] На третьем шаге записываем саму картинку в формате BMP из компонента Изображение (Image). Для этого необходим компонент Картинка-данные (BitmapStream), который преобразует картинку в формате BMP в массив байт, т.е. данные типа Stream. Заметьте, что данные в этом случае идут наоборот снизу вверх. Это сделано исключительно ради быстродействия операций с типом Stream. Как уже говорилось в начале статьи, данные Stream могут занимать как несколько байт, так и несколько десятков мегабайт, и даже больше. Каждое лишнее копирование такого объема данных приведет к значительным задержкам в работе программы и снизит её эффективность. Поэтому компонент Картинка-данные напрямую переписывает изображение в массив данных, указанный точкой Stream. На данном этапе важно понять еще одно свойство Stream данных, о котором немного упоминалось выше - это текущая позиция указателя чтения и записи данных, которую можно менять методом doPosition в пределах от 0 до (Size-1), где Size - это размер файла или размер массива данных в памяти (измеряется в байтах). Иначе говоря, указатель определяет, с какого байта в массиве читать и писать данные. Так, после записи комментариев позиция указателя автоматически сместилась на <Длина строки>+1, +1 потому, что кроме самого текста мы еще записали на конце 0. Соответственно, следующая запись данных будет происходить сразу после комментариев пользователя. Теперь формат файла будет выглядеть так: <Комментарий><0><Картинка>.
  • И последним шагом нужно закрыть файл методом doClose. Необходимо это потому, что Windows при работе с файлами кэширует записи в оперативной памяти для ускорения работы с ними. Если вы не выполните doClose, то часть данных (если не все) будут неизбежно потеряны. Кроме того, пока работает программа и файл находится в открытом состоянии (это касается и режима чтения) никто больше не может получить доступ к нему.
       Откройте в конструкторе схему просмотрщика:

    
    Add(MainForm,93819,273,245)
    {
    Left=21
    Top=105
    }
    Add(Image,84162,539,308)
    {
    Left=90
    Top=30
    Width=295
    Height=240
    Color=16777215
    }
    Add(ODialog,8153,385,203)
    {
    link(onExecute,75081:doOpen,[])
    }
    Add(Edit,10768,441,266)
    {
    Left=90
    Top=5
    Width=295
    Height=21
    Font=[Arial,8,0,0,1]
    Text=""
    }
    Add(BitmapStream,60179,483,308)
    {
    link(onRead,84162:doLoad,[])
    link(Stream,9870997:Var3,[(489,254)])
    }
    Add(Button,27238,273,203)
    {
    Left=10
    Top=10
    Font=[Arial,8,0,0,1]
    Caption="Load"
    link(onClick,57202:doEvent1,[])
    }
    Add(DataToFile,69888,392,266)
    {
    Type=6
    link(onGet,10768:doText,[])
    link(Stream,9870997:Var1,[(398,254)])
    }
    Add(Hub,57202,336,203)
    {
    OutCount=4
    link(onEvent1,8153:doExecute,[])
    link(onEvent2,69888:doGet,[(374,216)(374,279)])
    link(onEvent3,60179:doRead,[(366,223)(366,314)])
    link(onEvent4,75081:doClose,[(428,230)(428,216)])
    }
    Add(FileStream,75081,441,203)
    {
    }
    Add(GetDataEx,9870997,434,245)
    {
    link(Data,75081:Stream,[])
    }
       Он строется по той же самой схеме, только настроенной на чтение данных: диалог сохранения файла изменен на диалог открытия файла, св-во Mode компонента Файловый поток изменено на Read, а линии связей с точек doPut компонента Данные в файл и doWrite компонента Картинка-данные перенесены на doGet и doRead соответственно. Теперь если выбрать файл ранее созданный и записанный на диск Редактором, то мы увидим на форме картинку и комментарий в ней.
  • BB-code статьи для вставки
    Всего комментариев: 0
    (комментарии к статье еще не добавлены)
    Комментарий
    ...