Класс 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;
}
//---------------------------------------------------------------------------

Вот так вот.

 

 

 
« Предыдущая статья