Navigation: Language Reference > 4 - Entity Declarations > File Structures >====== BLOB (declare a variable-length field) ====== | |
label | BLOB [,BINARY] [,NAME( )] |
Label | The label of the BLOB (PROP:Label). |
BLOB | Declares a variable-length string stored on disk per record which may be greater than 64K |
BINARY | Declares the BLOB a storage area for binary data (PROP:BINARY). |
NAME | Specifies the disk filename for the BLOB field (PROP:NAME). |
BLOB (Binary Large Object) declares a string field which is completely variable-length and may be greater than 64K in size. A BLOB must be declared before the RECORD structure. Generally, up to 255 BLOB fields may be declared in a FILE structure (the exact number and their manner of storage on disk is file driver dependent).
A BLOB may not be used as a variable–you may not name a BLOB as a control's USE attribute, or directly assign data to or from the BLOB.
You can use PROP:Handle to get the Windows handle to the BLOB entity and assign one BLOB to another: get the handle of both BLOB entities and then assign one BLOB's handle to the other BLOB's handle. A BLOB may not be accessed “as a whole;” you must either use Clarion's string slicing syntax to access the data (unlimited in 32-bit), or PROP:ImageBlob. The individual bytes of data in the BLOB are numbered starting with zero (0), not one (1). PROP:Handle when used with BLOB returns a Windows Global Memory Object Handle for use with low-level Windows GlobalXxxx() API calls that require it.
The SIZE procedure returns the number of bytes contained in the BLOB field for the current record in memory. You can also get (and set) the size of a BLOB using PROP:Size. You may set the size of the BLOB before assigning data to a new BLOB using string slicing, but it is not necessary as the size is automatically set by the string slice operation. You can also use PROP:ImageBlob to store and retrieve graphic images without first setting PROP:Size. It is a good idea to first set PROP:Size to zero (0) before assigning data to a BLOB that has not previously contained data, to eliminate any “junk” leftover from any previously accessed BLOB. When assigning from one BLOB to another using PROP:Handle, you may need to use PROP:Size to adjust the size of the destination BLOB to the size of the source BLOB. PROP:Touched can be used to determine if the contents of the BLOB has changed since it was retrieved from disk.
BLOB fields are not in the RECORD structure, and should not be listed in a PROP:SQL. If you need to retrieve an image field from an SQL backend, use SET/NEXT and BLOB syntax to retrieve the blob data.
Example:
ArchiveFile PROCEDURE
Names FILE,DRIVER('TopSpeed')
NaneKey KEY(Name)
Notes BLOB !Can be larger than 64K
Rec RECORD
Name STRING(20)
END
END
ArcNames FILE,DRIVER('TopSpeed')
Notes BLOB
Rec RECORD
Name STRING(20)
END
END
CODE
SET(Names)
LOOP
NEXT(Names)
IF ERRORCODE() THEN BREAK.
ArcNames.Rec = Names.Rec !Assign rec data to Archive
ArcNames.Notes{PROP:Handle} = Names.Notes{PROP:Handle} !Assign BLOB to Archive
IF ERRORCODE() = 80
MESSAGE('BLOB size is too large')
BREAK
END
ArcNames.Notes{PROP:Size} = Names.Notes{PROP:Size} ! and adjust the size
ADD(ArcNames)
END
StoreFileInBlob PROCEDURE !Stores any disk file into a BLOB
DosFileName STRING(260),STATIC
LastRec LONG
SavPtr LONG(1) !Start at 1
FileSize LONG
DosFile FILE,DRIVER('DOS'),PRE(DOS),NAME(DosFileName)
Record RECORD
F1 STRING(2000)
END
END
BlobStorage FILE,DRIVER('TopSpeed'),PRE(STO)
File BLOB,BINARY
Record RECORD
FileName STRING(64)
END
END
CODE
IF NOT FILEDIALOG('Choose File to Store',DosFileName,,0010b) THEN RETURN.
OPEN(BlobStorage) !Open the BLOB file
STO:FileName = DosFileName ! and store the filename
OPEN(DosFile) !Open the file
FileSize = BYTES(DosFile) !Get size of file
STO:File{PROP:Size} = FileSize ! and set the BLOB to store the file
LastRec = FileSize % SIZE(DOS:Record) !Check for short record at end of file
LOOP INT(FileSize/SIZE(DOS:Record)) TIMES
GET(DosFile,SavPtr) !Get each record
ASSERT(NOT ERRORCODE())
STO:File[SavPtr - 1 : SavPtr + SIZE(DOS:Record) - 2] = DOS:Record
!String slice data into BLOB
SavPtr += SIZE(DOS:Record) !Compute next record pointer
END
IF LastRec !If short record at end of file
GET(DosFile,SavPtr) !Get last record
ASSERT(BYTES(DosFile) = LastRec) ! size read should match computed size
STO:File[SavPtr - 1 : SavPtr + LastRec - 2] = DOS:Record
END
ADD(BlobStorage)
ASSERT(NOT ERRORCODE())
CLOSE(DosFile);CLOSE(BlobStorage)
See Also: