Класс TFileStream. Понятие потока VCL.

Сначала я бы хотел бы дать некоторое вступление по поводу поточных классов VCL. Эти классы есть некоторое подобие альтернативы поточным классам C++. Как обычно в таких случаях с VCL, основной TStream класс никто впрямую не использует, от него можно только наследовать. Прямым потомком TStream является класс THandleStream, который некоторым образом интегрирован с оболочкой (я в смысле - Виндовсом). Дело в том, что в WinAPI есть такая категория функций, которые выдают (или используют в качестве параметра) дескрипторп потока. Как раз таким дескриптором и обладает класс THandleStream. Как обычно, все функции, предоставляемые API, довольно сложны в использовании, и загромождают программу ненужными ухищрениями. Поэтому и был создан этот самый класс.

Собственно от THandleStream произведен только класс TFileStream. Остальные из категории поточных произведены от TStream. Ну, мы рассматриваем TFileStream, так что этим и займемся.

Handle

Свойство, унаследованное от THandleStream. Определяет дескриптор потока. Этот дескриптор используется в вызовах функций WinApi. А, еще про WinAPI. Вот, мне писал один человек, как бы это получить активность с COM-порта. В принципе активность можно получить с любого порта, LPT, RS232 или еще чего. Правда последний - тот же COM в более современном исполнении. Есть такая функция WaitCommEvent. В данном случае Comm - не ошибка, а аббревиатура communication device.

Так вот, она через Handle порта позволяет ждать от него активности. Для нее наш дескриптор тоже подходит. Создавать файл нужно как одно из имен типа COM1, COM2, COM3, LPT1 и так далее. Для связи с VxD устройствами необходим путь типа "\\.\a". Последний открывает дескриптор для дисковода [a:]. Связь с портами - довольно обширная тема. Поэтому я рассмотрю ее позже.

Size

Содержит информацию о размере потока (в байтах). Можно установить это свойство для того, чтобы "обрезать" поток. Должен заметить, что не рекомендуется использовать это свойство с портами и именованными pipe. Pipe - механизм, обеспечивающий двунаправленный поток, туннель данных между процессами.

Position

Свойство, определяющее текущую позицию указателя потока. Более четко - количество считанных байтов от начала потока.

Теперь нужно и методы рассмотреть.

Конструктор TFileStream

Этот конструктор использует два параметра - имя создаваемого файла (AnsiString) и режим открытия. режим открытия задает типы операций и права доступа, применимые к данному объекту. Могут быть следующие значения, комбинируемые с помощью binary or оператора "|".

  • fmCreate
    создать новый файл. Если файл существует, то открывается в режиме чтения.
  • fmOpenRead
    открыть для чтения.
  • fmOpenWrite
    открыть для записи.
  • fmOpenReadWrite
    открыть и для того, и для другого.
  • fmShareCompat
    совмещенный режим доступа.
  • fmShareExclusive
    эксклюзивный режим. Ни одно приложение не может читать или записывать открытый файл.
  • fmShareDenyWrite
    запрет по записи для других приложений.
  • fmShareDenyRead
    запрет по чтению.
  • fmShareDenyNone
    никакого разделения ресурса.

Read, Write, Seek

Первые два в качестве параметра используют преременную void* и целое, определяющее длину считываемой/записываемой порции данных. Ну а Seek вообще очень похоже на fseek. Вот примеры использования функции:

TFileStream* stream=new TFileStream("c:\\test.txt",fmOpenReadWrite|fmShareExclusive)
//на всякий случай займем этот файл как эксклюзив ;)
stream->Seek(0,soFromBeginning);

Этот пример иллюстрирует возможность создания формата (полностью демонстрационного) для хранения изображений. В общем-то являясь уступающим аналогом DIB (по нашему - BMP), тем не менее я думаю это хороший пример.

Некоторая оговорка. Я не говорю, что TFileStream вообще и в данном случае - наилучший вариант поточного io класса. Например, можно было использовать fstream [basic_fstream]. Но все-таки это раздел, посвященный VCL и всему, что с ним связано. Поскольку программист на C++ Builder часто использует компонентные классы VCL, то ему приходится обращаться к сооствествующим поточным классам (потомкам TStream).

Алгоритм просто перписывает информацию в файл с указанием ширины и высоты изображения. Вообще-то это неэффективное использование массива Pixels и свойства ScanLine. В реальной программе для этого бы использовались функции WinAPI для прямой работы с матрицей, типа GetDIBits и SetDIBits. Но при использовании этих функций пример бы потерял выразительность.

Вот код:

//Эту функцию мне пришлось использовать из-за
// несовместимости формата DIB пикселей
// с выдаваемыми свойством Pixels
//Она переставляет R и B части цвета и удаляет высший байт..
long ConvertCol(long col)
{
col&=0x00FFFFFF;
long bcol=col;
bcol&=0x0000FF;
bcol*=0x10000;
long rcol=col;
rcol&=0xFF0000;
rcol/=0x10000;
long gcol=col;
gcol&=0x00FF00;
TColor result=(TColor)(rcol|gcol|bcol);
return result;
};
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::SaveClick(TObject *Sender)
{
TFileStream* fs=new TFileStream("test.xgr",fmCreate);
TVclBmp* bmp=new TVclBmp;
TColor *row;
TColor ptr;
int iptr;
int ns=sizeof(TColor);
bmp->Width=Image1->Picture->Bitmap->Width;
bmp->Height=Image1->Picture->Bitmap->Height;
TRect rect(0,0,Image1->Width,Image1->Height);
bmp->Canvas->CopyRect(rect,Image1->Picture->Bitmap->Canvas,rect);
iptr=bmp->Width;
fs->Write(&iptr,ns);
iptr=bmp->Height;
fs->Write(&iptr,ns);
Bar->Position=0;
Bar->Max=bmp->Height;
for(int i=0;iHeight;i++)
{
Bar->StepIt();
row=(TColor*)bmp->ScanLine[i];
fs->WriteBuffer(row,ns*bmp->Width);
};
delete fs;
delete bmp;
ScrollBox1Resize(0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::LoadClick(TObject *Sender)
{
TFileStream* fs=new TFileStream("test.xgr",fmOpenRead);
TVclBmp* bmp=new TVclBmp;
TColor ptr;
int ns=sizeof(TColor);
bmp->PixelFormat=pf32bit;
fs->Read(&ptr,ns);
bmp->Width=ptr;
fs->Read(&ptr,ns);
bmp->Height=ptr;
Bar->Position=0;
Bar->Max=bmp->Height;
for(int i=0;iHeight;i++)
{
Bar->StepIt();
for(int j=0;jWidth;j++)
{
fs->Read(&ptr,ns);
bmp->Canvas->Pixels[j][i]=ConvertCol(ptr);
};
};
Image2->Picture->Bitmap->Width=bmp->Width;
Image2->Picture->Bitmap->Height=bmp->Height;
Image2->Canvas->Draw(0,0,bmp);
delete fs;
delete bmp;
ScrollBox2Resize(0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::LoadFileClick(TObject *Sender)
{
if(!Open1->Execute())return;
Image1->Picture->LoadFromFile(Open1->FileName);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ScrollBox1Resize(TObject *Sender)
{
if(Image1->WidthClientRect.Width())
Image1->Left=(ScrollBox1->ClientRect.Width()-Image1->Width)/2;
else Image1->Left=0;
if(Image1->HeightClientRect.Height())
Image1->Top=(ScrollBox1->ClientRect.Height()-Image1->Height)/2;
else Image1->Top=0;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ScrollBox2Resize(TObject *Sender)
{
if(Image2->WidthClientRect.Width())
Image2->Left=(ScrollBox1->ClientRect.Width()-Image2->Width)/2;
else Image2->Left=0;
if(Image2->HeightClientRect.Height())
Image2->Top=(ScrollBox1->ClientRect.Height()-Image2->Height)/2;
else Image2->Top=0;
}
//---------------------------------------------------------------------------

Вот так вот.

 

 

Читайте также:
  • Назначение события во время выполнения программы
    Вот процедура, назначающая событие компонента обработчику события другого (или того же самого) компонента, где во время выполнения программа само событие и его обработчик заданы в виде строки. В случае неверных имен события или его обработчика процедура возбуждает исключительную ситуацию. Вы може...
  • Работа в фоне
    Я пишу программу в Delphi, которая каждый час должна проверять размер файла. Это также предполагает, что в случае неактивности приложения оно должно работать сторожевым псом в фоновом режиме win 95 и NT. Как мне сделать это...?? Вот некоторый исходный код, который должен делать то, что вы хотите....
  • Организация задержки
    Организация задержки - все еще большая головная в Delphi. Я использую Delphi 1 и пытаюсь организовать задержку 2 ms с погрешностью -0 ms +1 ms. Может кто-то уже решал подобную проблему? Организация цикла не позволяет достичь такой точности. Стандартный таймерный компонент не позволяет работать с ...
  • Получение имени обработчика события
    Имеется возможность получить значение указателя на обработчик события, который вы можете сравнить по адресу с другими методами, чтобы вычислить тот, которому передается данное событие: procedure TForm1.Button3Click(Sender: TObject); var P: record case Integer of 1: (E: TNotifyEvent); 2: (P: Point...
  • Делегирование события
    ...я вижу что событие делегировано, но почему вы считаете, что это отход от ООП? Тем не менее, Delphi это использует при каждом определении обработчика события. Вот как поступить в вашей ситуации:  Определите тип процедуры, использующейся в качестве обработчика события. Допустим, ваш обработ...